存档

2011年12月 的存档

Moving Box2d Bodies Like CCSprite Objects

2011年12月13日 没有评论

In cocos2d, you can ease in CCSprites and move them around in all kinds of ways. Most importantly – they can have easing in/out. For most games this is desirable for smooth movement etc.

id action = [CCMoveTo actionWithDuration:dur position:pos];
move = [CCEaseInOut actionWithAction:action rate:2];
[self runAction: move];

When moving a box2d body, the sprite attached to it is updated after the box2d step(). Moving the sprite and then updating the body is not an option here, as it entirely defeats the purpose of the physics framework.

So the other option, which I have successfully implemented, is to calculate the displacement, velocity and acceleration of a sprite by treating it as a mechanics entity in its own right. Each time I call my update() on the sprite so the character can decide where to move etc, my superclass also stores the previous position and velocity. These are stored as box2d compliant values by dividing by the PTM_RATIO.

In the subclass of CCSprite, called FMSprite:

-(CGPoint) displacement {
    return ccpSub(self.position, lastPos);
}

-(b2Vec2) getSpriteVelocity:(ccTime)dt {
    return b2Vec2(self.displacement.x / dt / PTM_RATIO,
                  self.displacement.y / dt / PTM_RATIO);
}

-(b2Vec2) getSpriteAccel:(ccTime)dt {
    b2Vec2 currVel = [self getSpriteVelocity:dt];
    if (dt == 0) {
        return b2Vec2(0,0);
    } else {    
        float accelX = (currVel.x - lastVel.x)/dt;
        float accelY = (currVel.y - lastVel.y)/dt;
        return b2Vec2(accelX, accelY);
    }
}

// This is called each update()
-(void) updateLast:(ccTime)dt {
    // MUST store lastVel before lastPos is updated since it uses displacement
    lastVel = [self getSpriteVelocity:dt];
    lastPos = ccp(self.X, self.Y);
}

// Leave this method untouched in subclasses
-(void) update:(ccTime)dt {
    [self updateObject:dt];

    // Store previous update values
    [self updateLast:dt];
}

// Override this method in subclasses for custom functionality
-(void) updateObject:(ccTime)dt {

}

I have then subclassed “FMSprite” into “FMObject”, which stores a b2Body etc.

In order to move the body, I must first move a sprite and track its acceleration, through which I can find the required force (using the mass) needed to follow the sprite’s motion. Since I can’t move the object’s sprite (which is synchronized to the body), I make another sprite called a “beacon”, add it as a child to the object, and move it around. All we need to do then is to have a function to synchronize the position of the box2d body with this beacon sprite using the forces I mentioned before.

-(void) followBeaconWithDelta:(ccTime)dt {
    float forceX = [beacon getSpriteAccel:dt].x * self.mass;
    float forceY = [beacon getSpriteAccel:dt].y * self.mass;
    [self addForce:b2Vec2(forceX, forceY)];
}

The result is brilliant, a smooth easing motion of the b2body moving where ever you want it to, without playing around with any of its own forces, but rather copying that of a CCSprite and replicating its motion. Since it’s all forces, it won’t cause jittering and distortions when colliding with other b2Body objects. If anyone has any other methods to do this, please post an answer. Thanks!

What I do is different from yours, but can also Moving Box2d Bodies Like CCSprite Objects and even use the CCAction.
The most important thing is to create an object that contain ccSprite and b2body.

@interface RigidBody : CCNode {
    b2Body *m_Body;
    CCSprite *m_Sprite;
}

And then, rewrite the setPosition method.

-(void)setPosition:(CGPoint)position
{
    CGPoint currentPosition = position_;
    b2Transform transform = self.body->GetTransform();
    b2Vec2 p = transform.p;
    float32 angle = self.body->GetAngle();
    p += [CCMethod toMeter:ccpSub(position, currentPosition)];
    self.body->SetTransform(p, angle);  
    position_ = position;
}

The setPosition method calculate how much the position change,and set it to the b2body.

I hope I have understanding your question and the answer is helpful for you…

分类: stackoverflow精选, unity3d 标签:

Surface view as a bitmap in android

2011年12月12日 没有评论

I’m using cocos2d.

Now I’ve added some images in the layer, and played around a bit.

I’m trying to save the whole screen as image file.

How can I do this?

It is my understanding that cocos2d-android also has a CCRenderTexture class with the saveBuffer method. In that case have a look at my CCRenderTexture demo program and blog post for cocos2d-iphone which gives you an example for how to create a screenshot using CCRenderTexture and saveBuffer. The same principle should be applicable to cocos2d-android.

The only way to capture the content of a SurfaceView is if you are rendering into it using OpenGL. You can use glReadPixels() to grab the content of the surface. If you are drawing onto the SurfaceView using a Canvas, you can simply create a Bitmap, create a new Canvas for that Bitmap and execute your drawing code with the new Canvas.

分类: cocos2d, stackoverflow精选 标签:

NSTextField, Is it difficult to add? I think

2011年12月3日 没有评论

I’ve made small game in Xcode 4.2.

After I played all game level, the high-score-input window will appear. I want to add NSTextField to here, so the player could type his name by keyboard.

I added NSTextField to OpenGlView, but I can’t see it on the screen. What’s the matter with this? I also try to add subview and add NSTextField, but I get the same result.

Xcode4.2, simulator is My Mac – 32bit.

    NSView *view = [[NSView alloc] initWithFrame:NSRectFromCGRect(CGRectMake(0, 0, 480, 320))];

    [[[CCDirector sharedDirector] openGLView] addSubview:view];

    [[view layer] setZPosition:1];
//        
    NSTextField *textField = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(0, 0, 100, 40))];
    [view addSubview:textField];

As the documentation for NSOpenGLView states, it does not support subviews:

“An NSOpenGLView object cannot have subviews. You can, however, divide
a single NSOpenGLView into multiple rendering areas using the
glViewport function.”

While I’m not sure whether you’re using your own NSOpenGLView subclass, or whether cocos2d provides a view itself, but it will likely have the same “limitations”.

The NSTextField could be in the same window, provided it’s located such that it doesn’t overlap the OpenGL view.

Otherwise, you could just implement that part of the UI in a separate NSWindow.

This sample project displays the dialog as a sheet, attached to the main window with the OpenGL view:

NSTextField, Is it difficult to add? I think

Project: OpenGLHighScore.zip

分类: stackoverflow精选, unity3d 标签:

Tap duration in cocos2d

2011年12月2日 没有评论

Any ideas how to handle tap duration in cocos2d?

I need to do something after the user holds his or her finger on a certain sprite for about 1-2 secs.

Thanks.

You need to do it the manual way:

  1. Add a BOOL flag ivar and a float ivar in your CCLayer subclass.
  2. On touch began, set the flag to TRUE and reset the float ivar to 0.0
  3. On touch moved, ended or cancelled, set the flag to FALSE.
  4. In the update or tick, increase the float ivar value by the dt amount. Check if that float ivar value to perform your logic if it is larger than your threshold value (1.0 or 2.0 seconds).

If you want to handle multiple touches, you might need a way to attach and differentiate the BOOL flag and float ivar combination to each touch.

I’d suggest creating an intermediate subclass between CCLayer and your implementation subclass so that you can hide the mechanism from the implementation subclass and also to allow easy reuse.

Save yourself a lot of manual work and use the UIGestureRecognizers for things like these. In this particular case you will want to use the UILongPressGestureRecognizer.

Btw, gesture recognizers are built-in, ready to use if you use Kobold2D.

To use a UILongPressGestureRecognizer, you can do something like this:

UILongPressGestureRecognizer* recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressFrom:)];
recognizer.minimumPressDuration = 2.0; // seconds
AppDelegate* appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate.viewController.view addGestureRecognizer:recognizer];

Your long press handler could look like this:

-(void)handleLongPressFrom:(UILongPressGestureRecognizer*)recognizer
{
    if(recognizer.state == UIGestureRecognizerStateEnded)
    {
        CCLOG(@"Long press gesture recognized.");

        // Get the location of the touch in Cocos coordinates.
        CGPoint touchLocation = [recognizer locationInView:recognizer.view];
        CCDirector* director = [CCDirector sharedDirector];
        touchLocation = [director convertToGL:touchLocation];
        touchLocation = [[director runningScene] convertToNodeSpace:touchLocation];

        // Your stuff.
    }
}

When you’re finished, don’t forget to remove it.

AppDelegate* appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate.viewController.view removeGestureRecognizer:recognizer];
分类: cocos2d, stackoverflow精选 标签: