0
votes

I'm developing a very simple game. Here's my enemy class named Machine's behavior code:

#import "Machine.h"

@implementation Machine

+(id)machineWithWorld:(b2World*)world position:(CGPoint)pos
{
    return [[[self alloc] initWithWorld:world position:pos] autorelease];
}

-(id)initWithWorld:(b2World*)world position:(CGPoint)pos
{
    if(self = [super initWithShape:[AppDelegate renameFrameForIpad:@"machine"] inWorld:world])
    {
        size = [CCDirector sharedDirector].winSize;

        self.body->SetTransform([Helper toMeters:pos], 0.0);
        self.body->SetType(b2_staticBody);

        safetyCounter = 5;
        [self schedule:@selector(machineSafetyCounter)];

        movementWidthInMeters = (size.width-self.contentSize.width)/PTM_RATIO;
        linearSpeed = 0.5;
        [self schedule:@selector(startMoving) interval:1.5];
    }

    return self;
}

#pragma mark<Machine Behavior>

-(void)startMoving
{
    [self unschedule:_cmd];

    float distanceFromCenterInMeters = (size.width/2 - self.position.x)/PTM_RATIO;
    float interval = ABS(distanceFromCenterInMeters/linearSpeed);
    if(interval < 0.01f)
        interval = 0.02f;

    b2Vec2 motionDirection = (distanceFromCenterInMeters > 0.0f) ? b2Vec2(1.0, 0.0) : b2Vec2(-1.0, 0.0);
    self.body->SetType(b2_kinematicBody);
    self.body->SetLinearVelocity(linearSpeed*motionDirection);

    [self schedule:@selector(startMotionFromBeginning) interval:interval-0.01];

    CCLOG(@"startMoving distance-->%f, interval-->%f", distanceFromCenterInMeters, interval);
}

-(void)startMotionFromBeginning
{
    [self unschedule:_cmd];

    float interval = (movementWidthInMeters/2)/linearSpeed;

    self.body->SetLinearVelocity(0.5*b2Vec2(1.0, 0.0));
    [self schedule:@selector(moveRTL) interval:interval-0.01];

    [self schedule:@selector(checkIfHelmetIsBelowMachine) interval:0.1];

    CCLOG(@"startMotionFromBeginning interval-->%f", interval);
}

-(void)moveRTL
{
    [self unschedule:_cmd];

    float interval = movementWidthInMeters/linearSpeed;

    self.body->SetLinearVelocity(0.5*b2Vec2(-1.0, 0.0));
    [self schedule:@selector(moveLTR) interval:interval-0.01];

    CCLOG(@"moveRTL interval-->%f", interval);
}

-(void)moveLTR
{
    [self unschedule:_cmd];

    float interval = movementWidthInMeters/linearSpeed;

    self.body->SetLinearVelocity(0.5*b2Vec2(1.0, 0.0));
    [self schedule:@selector(moveRTL) interval:interval-0.01];

    CCLOG(@"moveLTR interval-->%f", interval);
}

-(void)checkIfHelmetIsBelowMachine
{
    [self unschedule:_cmd];

    Helmet* helmet = (Helmet*)[[[[[CCDirector sharedDirector] runningScene] children] objectAtIndex:0] getChildByTag:kTagHelmet];
    float helmetPosX = helmet.position.x;

    if((self.position.x > helmetPosX) && (self.position.x < helmetPosX+helmet.contentSize.width))
    {
        [self unscheduleAllSelectors];
        [self schedule:@selector(machineSafetyCounter) interval:0.1];

        [self schedule:@selector(startMovingDownwards) interval:0.0];

        return;
    }

    [self schedule:_cmd interval:0.1];
}

-(void)startMovingDownwards
{
    [self unschedule:_cmd];

    self.body->SetLinearVelocity(0.25*b2Vec2(0.0, -1.0));
    [self schedule:@selector(stopMovingDownwards) interval:1.0];

    CCLOG(@"startMovingDownwards");
}

-(void)stopMovingDownwards
{
    [self unschedule:_cmd];

    self.body->SetLinearVelocity(b2Vec2(0.0, 0.0));
    [self schedule:@selector(startMoving) interval:0.2];

    CCLOG(@"stopMovingDownwards");
}

All I have done is following:

1) The body is static initially and is positioned at ccp(size.width*0.5, size.height*0.75).

2) After 1.5 seconds, It becomes kinematic and starts moving with a linear speed of 0.5 m/s.

3) It checks it's current distance (from screen width center keeping height same), evaluates the time needed to reach that spot, and then starts moving in that direction horizontally.

4) After reaching that spot, it starts it's signature motion, it starts moving from Left to right, if at any time helmet(another game object) passes underneath it, it starts moving down and stops after 1.0 seconds, then whole cycle repeats.

5) It moves LTR & RTL until it starts to move down when it finds the helmet underneath it.

Now the problem is, sometimes the behavior is exactly same as expected. And many many times, it starts moving upwards and I have never set the y bit for motion vector in positive direction.

1
Set a breakpoint (or add a log statement) in SetLinearVelocity, see if it ever receives a call with positive y coordinate.LearnCocos2D

1 Answers

0
votes

After initializing the body, you should not change its bodyType. When you first make the body, set it as kinematic so you don't run into problems later when trying to change it. Is the body attached to a CCSprite? If so, you should make the class a subclass of CCSprite so you can use
[super initWithFile:(NSString *) world:(b2World *)] or some method of your choosing to facilitate your endeavors.