代码之家  ›  专栏  ›  技术社区  ›  TheM00s3

停止精灵的移动-Box2D(cocos2d)

  •  1
  • TheM00s3  · 技术社区  · 10 年前

    我正在制作一个游戏,我需要一个只有在按下按钮时才能移动的物体。我有一个开始运动的方法,到目前为止,我通过破坏物体的身体来结束物体的运动。我遇到的问题是,我无法再次移动对象,因为程序现在将崩溃。我想知道是否有办法在尸体被摧毁后重建尸体,因为我目前检查尸体是否仍然存在的方法不起作用。

    这是我的代码。

    NSMutableArray *spaceObjectsArray;
    
    #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;
    }
    
    -(void)gameLogic:(ccTime)delta
    {
        [self addSpaceObjects];
    }
    
    -(void) addSpaceObjects
    {
    
        _spaceObject = [CCSprite spriteWithFile:@"blueDot.jpg"];
    
    
        //create spaceObject body
        b2BodyDef spaceObjectbBodyDef;
        spaceObjectbBodyDef.type=b2_dynamicBody;
        spaceObjectbBodyDef.userData = _spaceObject;
        //make the location of spaceObject
        CGSize winSize = [CCDirector sharedDirector].winSize;
        int minX= _spaceObject.contentSize.width/2;
        int maxX = winSize.width - _spaceObject.contentSize.width/2;
        int rangeX = maxX - minX;
        int actualX = (arc4random() % rangeX) + minX;
        _spaceObject.position = ccp(actualX, winSize.height + _ship.contentSize.height);
        spaceObjectbBodyDef.position.Set(actualX/PTM_RATIO, (winSize.height+_ship.contentSize.height)/PTM_RATIO);
        _spaceObjectBody= _world->CreateBody(&spaceObjectbBodyDef);
    
        //create spaceObject shape
        b2PolygonShape spaceObjectShape;
        spaceObjectShape.SetAsBox(_spaceObject.contentSize.width/PTM_RATIO/2, _spaceObject.contentSize.height/PTM_RATIO/2);
    
        //create spaceObject fixture
        b2FixtureDef spaceObjectShapeDef;
        spaceObjectShapeDef.shape= &spaceObjectShape;
        spaceObjectShapeDef.density = 2;
        spaceObjectShapeDef.restitution =0;
        spaceObjectShapeDef.friction=0;
        _spaceObjectFixture = _spaceObjectBody->CreateFixture(&spaceObjectShapeDef);
    
        [self addChild:_spaceObject];
        _spaceObject.tag=1;
        [spaceObjectsArray addObject:_spaceObject];
    
       //aply force on the object
        int randomValue = ((arc4random() % 5) *-1);
        b2Vec2 force = b2Vec2(0,randomValue);
        _spaceObjectBody ->ApplyLinearImpulse(force, _spaceObjectBody->GetPosition());
    
    
    }
    

    包含主体创建和定义的init方法

    -(id) init
    {
        if( (self=[super init])) {
    
            CGSize s = [CCDirector sharedDirector].winSize;
    
    
            //create spaceShip sprite and add it to the layer
            _ship = [CCSprite spriteWithFile:@"theShip.gif" ];
            _ship.position = ccp(s.width/2, 1.25*_ship.contentSize.height);
            [self addChild:_ship];
    
            //create the world
            b2Vec2 gravity = b2Vec2_zero;
            _world = new b2World(gravity);
    
            //create ship body
            b2BodyDef shipBodyDef;
            shipBodyDef.type = b2_dynamicBody;
            shipBodyDef.position.Set((s.width/2)/PTM_RATIO, (1.25*_ship.contentSize.height)/PTM_RATIO);
            shipBodyDef.userData = _ship;
    
            if(_shipBody == NULL){
            _shipBody =_world->CreateBody(&shipBodyDef);
            }
    
            //create ship shape
            b2PolygonShape shipShape;
            shipShape.SetAsBox(_ship.contentSize.width/PTM_RATIO/2, _ship.contentSize.height/PTM_RATIO/2);
    
            //create Ship definition and add to body
            b2FixtureDef ShipShapeDef;
            ShipShapeDef.shape = &shipShape;
            ShipShapeDef.density = 3;
            ShipShapeDef.friction =0;
            ShipShapeDef.restitution =0;
            _shipFixture = _shipBody->CreateFixture(&ShipShapeDef);
    
            //make the paddles
            //bottom left one
            _paddle1 = [CCSprite spriteWithFile:@"spritePaddle.jpeg"];
            int bottomOfScreenX = 0 + _paddle1.contentSize.width/2;
            int bottomOfScreenY = 0+_paddle1.contentSize.height/2;
            _paddle1.position = ccp(bottomOfScreenX,bottomOfScreenY);
            [self addChild:_paddle1];
            //bottom right one
            _paddle2 = [CCSprite spriteWithFile:@"spritePaddle.jpeg"];
            int bottomRightOfScreenX = s.width - _paddle2.contentSize.width/2;
            _paddle2.position = ccp(bottomRightOfScreenX, bottomOfScreenY);
            [self addChild:_paddle2];
    
    
            //continuously spawn spaceObjects
            [self schedule:@selector(gameLogic:) interval:1];
    
    
            // enable events
    
            self.touchEnabled = YES;
    
    
    
            // init physics
            [self schedule:@selector(tick:)];
    
    
        }
        return self;
    }
    
    -(void)tick:(ccTime) delta
    {//this method is to simulate physics and to test for the position of where objects should be if force has been applied to them
        _world->Step(delta, 8, 8);
        for (b2Body *b=_world->GetBodyList(); b; b=b->GetNext()){
            if (b->GetUserData() != NULL){
                CCSprite *shipData = (CCSprite *)b->GetUserData();
                shipData.position = ccp(b->GetPosition().x *PTM_RATIO, b->GetPosition().y *PTM_RATIO);
            }
        }
    }
    

    移动船的桨是合乎逻辑的

    -(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        //Set up a way for touches to be turned into locations onscreen
        NSSet *allTouches = [event allTouches];
        UITouch *touch = [allTouches anyObject];
        CGPoint location = [touch locationInView:[touch view]];
        location = [[CCDirector sharedDirector] convertToGL:location ];
    
        //check to see if Left Paddle is being pressed
        if (CGRectContainsPoint([_paddle1 boundingBox], location)){
            b2Vec2 force = b2Vec2(-5,0);
            _shipBody->ApplyLinearImpulse(force, _shipBody ->GetPosition());
            }
        if (CGRectContainsPoint([_paddle2 boundingBox], location)){
            b2Vec2 force = b2Vec2(5,0);
            _shipBody->ApplyLinearImpulse(force, _shipBody->GetPosition());
        }
    }
    

    桨箱不再被触摸逻辑

    -(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        _world->DestroyBody(_shipBody);
    
    }
    -(void) dealloc
    {
        delete _world;
        _world = NULL;
    
    
    
        [super dealloc];
    }   
    
    @end
    
    1 回复  |  直到 10 年前
        1
  •  0
  •   FuzzyBunnySlippers    10 年前

    摧毁身体以结束其运动并不是最好的解决方案。只有当你真的不想让身体成为模拟的一部分时,你才应该移除它。

    有几种停止身体运动的选项:

    1-将其线速度设置为0。这将使其立即停止。如果有其他事情在推动它(例如与身体接触),你必须决定该怎么做。

    body->SetLinearVelocity(b2Vec2(0,0)));
    

    2-将其线性/角度阻尼设置为0。这将消散它所具有的动力,因此它将缓慢停止。您使用的系数应大于0。随着数值的增大,身体会更快地停止 它将抵抗来自其他身体的运动(如果他们撞到它,它将减速并再次停止)。当您希望身体开始移动时,请记住将线性/角度阻尼转回0。

    body->SetLinearDamping(0.2);
    
    body->SetAngularDamping(0.2);
    

    3-给它一个目标位置 寻找 这基本上是一个反馈控制回路,在那里你施加一个力,让它朝着你希望身体停留的地方移动。它可以用于使身体遵循路径等。下面的代码是更大代码库的一部分( you can see it here ),但你应该能大致了解。该功能向物体施加推力,使其朝目标推进。

    void MovingEntity::ApplyThrust()
    {
       // Get the distance to the target.
       b2Vec2 toTarget = GetTargetPos() - GetBody()->GetWorldCenter();
       toTarget.Normalize();
       b2Vec2 desiredVel = GetMaxSpeed()*toTarget;
       b2Vec2 currentVel = GetBody()->GetLinearVelocity();
       b2Vec2 thrust = GetMaxLinearAcceleration()*(desiredVel - currentVel);
       GetBody()->ApplyForceToCenter(thrust);
    }