applyforce inconsistent behavior

Here's the place to get help and discuss features. The focus is on the C++ version, but generic questions are welcome.
zase
Posts: 10
Joined: Thu Dec 06, 2012 8:18 am

applyforce inconsistent behavior

Postby zase » Sun Mar 19, 2017 9:23 pm

I am using box2d to simulate projectile motion from a cannon. I am calculating the angle and distance between the cannon barrel and the crosshair. The greater the distance between the crosshair and the barrel the larger the force. I am running this program on Xcode 8.2.1 and cocos2d. When I run my program on the iPad air I see inconsistent behavior. For example, as I increase the distance I expect the force to increase, and as a result I expect the distance the projectile travels to be longer, but I am not seeing this behavior. I decrease the distance between the barrel and the crosshair and the projectile flies farther. Below is the code I am using. I know that box2d is not deterministic and I have tried applyForce, applyLinerarImpulse, and setLinearVelocity, but I cannot get the behavior correct. I want the force to be less when the distance is less, and the force to be greater when the distance is greater. Below is my code. Any help is appreciated.

Code: Select all

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   
    if( self.boulderFired || gamePaused)
    {
        bulletStartingVelocity = b2Vec2(0,0);
        bulletStartingPosition = b2Vec2(0,0);
        return;
    }

    NSLog(@"began");
    UITouch *myTouch = [touches anyObject];
    CGPoint location = [myTouch locationInView:[myTouch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];

    float angleDegree, angleRadian;
    int direction =1;
    if(self.hud.isSoundOn)
        [self.musicInterface playAudioStartTouch];
   
    float distanceX = ( (location.x/PTM_RATIO) - (barrel.position.x/PTM_RATIO) );
    float distanceY = ( (location.y/PTM_RATIO) - (barrel.position.y/PTM_RATIO) );
    if (fabsf(distanceX)>18*(screenSize.height/designSizeHeight)*(screenSize.width/designSizeWidth) ||
        fabsf(distanceY)>18*(screenSize.height/designSizeHeight)*(screenSize.width/designSizeWidth))
    {
        bulletStartingVelocity = b2Vec2(0,0);
        bulletStartingPosition = b2Vec2(0,0);
        return;
    }
    if(barrel.position.x<location.x)
    {
        angleRadian = atanf(distanceY/distanceX);
        angleDegree = CC_RADIANS_TO_DEGREES(angleRadian);
       
    }
    else
    {
        angleRadian = atanf(distanceY/distanceX);
        angleDegree =180 + CC_RADIANS_TO_DEGREES(angleRadian);
        direction=-1;
       
    }
   

    slingPosition = ccp(barrel.position.x, (barrel.position.y+15/scaleFactorSpriteResolution));
    barrel.rotation = (angleDegree*-1);
   
 
    if (distanceX*distanceX+distanceY*distanceY>(17*(screenSize.height/designSizeHeight)*(screenSize.width/designSizeWidth)))
    {
        CGFloat angleTemp = atan2f(distanceY,distanceX);
        CGPoint tempStandPos = [self scalePoint:ccp(35,135)];
        CGPoint tempBarrelPos = [self scalePoint:ccp(65,165)];
        location.x=tempBarrelPos.x+tempStandPos.y*cosf(angleTemp);
        location.y=tempBarrelPos.y+tempStandPos.y*sinf(angleTemp);

       
    }

    crossHair.position = ccp(location.x, location.y);
    distanceX = ( (crossHair.position.x/PTM_RATIO) - (slingPosition.x/PTM_RATIO) );
    distanceY = ( (crossHair.position.y/PTM_RATIO) - (slingPosition.y/PTM_RATIO) );
    float distance = sqrtf(distanceX*distanceX+distanceY*distanceY)*direction;
    bulletStartingPosition = b2Vec2(slingPosition.x, slingPosition.y);
    //bulletStartingVelocity = b2Vec2(cosf(angleRadian)*(distance/scaleFactorSpriteResolution),sinf(angleRadian)*(distance/scaleFactorSpriteResolution));
    bulletStartingVelocity = b2Vec2(cosf(angleRadian)*(distance*10),sinf(angleRadian)*(distance*10));
   
 
    if(sniperOn)
        [self drawProjectilePath:b2Vec2(barrel.position.x, barrel.position.y) withVelocity:b2Vec2(cosf(angleRadian)*(distance*23.895),sinf(angleRadian)*(distance*23.895))];
   
    //   [self drawProjectilePath:bulletStartingPosition :b2Vec2(cosf(angleRadian)*distance*56.595,sinf(angleRadian)*distance*56.595)];
    //[self drawProjectilePath:bulletStartingPosition :bulletStartingVelocity];

}
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"move start");
    if( self.boulderFired || gamePaused)
    {
        bulletStartingVelocity = b2Vec2(0,0);
        bulletStartingPosition = b2Vec2(0,0);
        return;
    }
   

    UITouch *myTouch = [[touches allObjects] objectAtIndex:0];
   
    CGPoint location = [myTouch locationInView:[myTouch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];
    float angleDegree, angleRadian;
    int direction=1;
    float distanceX = ( (location.x/PTM_RATIO) - (barrel.position.x/PTM_RATIO) );
    float distanceY = ( (location.y/PTM_RATIO) - (barrel.position.y/PTM_RATIO) );
    if (fabsf(distanceX)>18*(screenSize.height/designSizeHeight)*(screenSize.width/designSizeWidth) ||
        fabsf(distanceY)>18*(screenSize.height/designSizeHeight)*(screenSize.width/designSizeWidth))
    {
        bulletStartingVelocity = b2Vec2(0,0);
        bulletStartingPosition = b2Vec2(0,0);
        return;
    }
    if(barrel.position.x<location.x)
    {
        angleRadian = atanf(distanceY/distanceX);
        angleDegree = CC_RADIANS_TO_DEGREES(angleRadian);
       
    }
    else
    {
        angleRadian = atanf(distanceY/distanceX);
        angleDegree =180 + CC_RADIANS_TO_DEGREES(angleRadian);
        direction=-1;
       
    }
   

    barrel.rotation = (angleDegree*-1);

   
   
    if (distanceX*distanceX+distanceY*distanceY>(17*(screenSize.height/designSizeHeight)*(screenSize.width/designSizeWidth)))
    {
        CGFloat angleTemp = atan2f(distanceY,distanceX);
        CGPoint tempStandPos = [self scalePoint:ccp(35,135)];
        CGPoint tempBarrelPos = [self scalePoint:ccp(65,165)];
        location.x=tempBarrelPos.x+tempStandPos.y*cosf(angleTemp);
        location.y=tempBarrelPos.y+tempStandPos.y*sinf(angleTemp);
       

       
    }
    crossHair.position = ccp(location.x, location.y);
    distanceX = ( (crossHair.position.x/PTM_RATIO) - (slingPosition.x/PTM_RATIO) );
    distanceY = ( (crossHair.position.y/PTM_RATIO) - (slingPosition.y/PTM_RATIO) );
   
    float distance = sqrtf(distanceX*distanceX+distanceY*distanceY)*direction;

    bulletStartingPosition = b2Vec2(slingPosition.x, slingPosition.y);
    //bulletStartingVelocity = b2Vec2(cosf(angleRadian)*(distance/scaleFactorSpriteResolution),sinf(angleRadian)*(distance/scaleFactorSpriteResolution));
    bulletStartingVelocity = b2Vec2(cosf(angleRadian)*(distance*10),sinf(angleRadian)*(distance*10));
   

   
    if(sniperOn)
        [self drawProjectilePath:b2Vec2(barrel.position.x, barrel.position.y) withVelocity:b2Vec2(cosf(angleRadian)*(distance*23.895),sinf(angleRadian)*(distance*23.895))];
   
    //   [self drawProjectilePath:bulletStartingPosition :b2Vec2(cosf(angleRadian)*distance*56.595,sinf(angleRadian)*distance*56.595)];
    //[self drawProjectilePath:bulletStartingPosition :bulletStartingVelocity];

}

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if(gamePaused )
    {
        bulletStartingVelocity = b2Vec2(0,0);
        bulletStartingPosition = b2Vec2(0,0);
        return;
    }
    NSLog(@"ended");
   

   

    if(!self.boulderFired)
    {
       
        [self createBullets:slingPosition];
        bullet->SetActive(true);
        NSLog(@"ending starting position %f and %f", bulletStartingPosition.x, bulletStartingPosition.y);
        NSLog(@"ending began starting velocity %f and %f", bulletStartingVelocity.x, bulletStartingVelocity.y);
        //bullet->ApplyForce(bulletStartingVelocity, bulletStartingPosition);
        bullet->SetLinearVelocity(bulletStartingVelocity);
        self.boulderFired = true;
        [self enableGestureSwipes:true];
       

        bulletStartingVelocity = b2Vec2(0,0);
        bulletStartingPosition = b2Vec2(0,0);
    }
   
}

zase
Posts: 10
Joined: Thu Dec 06, 2012 8:18 am

Re: applyforce inconsistent behavior

Postby zase » Fri Mar 24, 2017 12:19 pm

Btw I am testing on both an actual iPad and the iPad Air on the apple simulator. When I run the simulator I am seeing the issue. I know the simulator is not the 100% reliable, but I want to spot check as much devices as I can. Could the issue be with the simulator and not the code?

Louis Langholtz
Posts: 20
Joined: Tue Dec 20, 2016 10:53 am

Re: applyforce inconsistent behavior

Postby Louis Langholtz » Tue Mar 28, 2017 9:04 am

Hello and welcome to the Box2D forums.

I don't know that I can answer your question but wanted to address it anyway in the hopes of possibly helping. In your initial post you made some statements that I'd like to address:

When I run my program on the iPad air I see inconsistent behavior.


From your second post it sounds like by inconsistent behavior you mean that you're comparing the behavior between running on actual hardware versus running on a simulator of the hardware and seeing differences between them. Is my understanding of this correct?

I know that box2d is not deterministic
.
This may be an incorrect presumption however. In what way do you mean "deterministic"?

Box2D is 100% repeatable. I've seen 100% repeatability in my testing of Box2D and in my analysis of its source code. Erin Cato (the author of Box2D) also states this in several places I've seen.

The only inconsistency that I've heard of cropping up is when comparing results of Box2D simulations between differing implementations of floating point processing. So this might explain some of the differences that you're seeing between running Box2D on actual hardware versus running it on a simulator of that hardware (depending of course on how exact the simulator is in simulating the hardware).

On looking at your code, admittedly there's more of it right now than I want to fully parse so I have only skimmed over it.

While I suspect it's unlikely to be catastrophic cancelation that is causing the problem you're noticing, I do believe the potential for catastrophic cancelation is something everyone using floating point math should be aware of and keep in mind regarding what can go very wrong (with floating point math). I say that this is unlikely (unlikely to be the main problem at least), because it sounds like the problem gets proportionately worse as the distance between the crosshair and the barrel increases.

From what you're seeing, is inverse linear proportionality indeed a valid assessment of the behavior then? Inverse to what you're intending I mean? That'd suggest to me that perhaps the coordinates are reversed for some reason like perhaps positive Y is down instead of up (or vice versa from the expected orientation). Can you confirm whether that is or is not the problem?

As to whether the issue is with the simulator and not the code, that certainly seems possible to me. If it were me though, I'd feel uncomfortable with just chalking the problem up to that and not figuring it out fully. When I have used SFML with Box2D on the simulator and actual iPhone hardware I do recall encountering some gotcha's but unfortunately not whether any are relevant to the problem you're seeing.

If you do nail down what the problem is/was, please do let us know. Good luck!

zase
Posts: 10
Joined: Thu Dec 06, 2012 8:18 am

Re: applyforce inconsistent behavior

Postby zase » Thu Apr 20, 2017 12:49 pm

Sorry for the delay. The discrepancy is completely random. By this I mean it doesn't matter what the distance is between the barrel and the cross hair. I think you are right about the error being with xcode. As the code runs ok on the actual device. Luckily I updated xcode and that seemed to fix the error on the simulator.


Return to “General Discussion”



Who is online

Users browsing this forum: No registered users and 3 guests