Skip to content

Instantly share code, notes, and snippets.

@sdabet
Last active August 18, 2019 12:50
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save sdabet/08a6f41415c5e3b8be0f to your computer and use it in GitHub Desktop.
Save sdabet/08a6f41415c5e3b8be0f to your computer and use it in GitHub Desktop.
#import "CCSprite.h"
@interface SoftBubble : CCSprite
@end
#import "SoftBubble.h"
#import "cocos2d.h"
#import "CCTexture_Private.h"
static const int NUM_SEGMENTS = 20;
static const float PHYSICS_BODY_RADIUS = 4;
static const float INNER_STIFFNESS = 1500;
static const float INNER_DAMPING = 50;
static const float OUTER_STIFFNESS = 1000;
static const float OUTER_DAMPING = 50;
@implementation SoftBubble
- (id)initWithImageNamed:(NSString*)imageName;
{
self = [super initWithImageNamed:imageName];
if (self) {
// Bubble radius is the the texture half-width
float bubbleRadius = self.contentSize.width/2;
// Main body at the center of the bubble
self.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:PHYSICS_BODY_RADIUS andCenter:CGPointMake(bubbleRadius, bubbleRadius)];
self.physicsBody.allowsRotation = false;
// Distance between main body and outer children
float childDist = bubbleRadius - PHYSICS_BODY_RADIUS;
// Create child bodies connected to the main body with inner springs
for(int i=0; i<NUM_SEGMENTS; i++) {
float childAngle = i * 2 * M_PI / NUM_SEGMENTS;
CCNode *child = [CCNode node];
child.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:PHYSICS_BODY_RADIUS andCenter:CGPointZero];
child.physicsBody.allowsRotation = false;
child.position = ccp(bubbleRadius + childDist * cosf(childAngle), bubbleRadius + childDist * sinf(childAngle));
[self addChild:child];
[CCPhysicsJoint connectedSpringJointWithBodyA:self.physicsBody
bodyB:child.physicsBody
anchorA:CGPointMake(bubbleRadius, bubbleRadius)
anchorB:CGPointZero
restLength:childDist
stiffness:INNER_STIFFNESS damping:INNER_DAMPING];
}
// Connect child bodies together with outer springs
for(int i=0; i<NUM_SEGMENTS; i++) {
CCNode *previous = i==0 ? self.children[NUM_SEGMENTS-1] : self.children[i-1];
CCNode *child = self.children[i];
[CCPhysicsJoint connectedSpringJointWithBodyA:child.physicsBody
bodyB:previous.physicsBody
anchorA:CGPointZero
anchorB:CGPointZero
restLength:childDist*2*M_PI/NUM_SEGMENTS
stiffness:OUTER_STIFFNESS
damping:OUTER_DAMPING];
}
}
return self;
}
// Map the texture on the physics bodies with a triangle fan
- (void) draw {
int nVertices = NUM_SEGMENTS+2;
float deltaAngle = (2.f * M_PI) / NUM_SEGMENTS;
float bubbleRadius = self.contentSize.width/2;
// Triangle fan vertices
ccVertex2F vertices[nVertices];
vertices[0] = (ccVertex2F){bubbleRadius, bubbleRadius};
for (int i = 0; i < NUM_SEGMENTS; i++) {
CCNode *child = self.children[i];
vertices[i+1] = (ccVertex2F){
child.position.x + PHYSICS_BODY_RADIUS * (child.position.x-bubbleRadius)/bubbleRadius,
child.position.y + PHYSICS_BODY_RADIUS * (child.position.y-bubbleRadius)/bubbleRadius
};
}
vertices[NUM_SEGMENTS+1] = vertices[1];
// Corresponding texture coordinates
ccVertex2F texCoords[nVertices];
texCoords[0] = (ccVertex2F){0.5f, 0.5f};
for (int i = 0; i < NUM_SEGMENTS; i++) {
GLfloat coordAngle = M_PI + (deltaAngle * i);
texCoords[i+1] = (ccVertex2F){0.5 + cosf(coordAngle)*0.5, 0.5 + sinf(coordAngle)*0.5};
}
texCoords[NUM_SEGMENTS+1] = texCoords[1];
// Default colors
ccColor4F colors[nVertices];
for (int i = 0; i <= NUM_SEGMENTS+1; i++) {
colors[i] = (ccColor4F){1, 1, 1, 1};
}
// Draw the triangle fan
CC_NODE_DRAW_SETUP();
ccGLBlendFunc(self.blendFunc.src, self.blendFunc.dst);
ccGLBindTexture2D(self.texture.name);
ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );
glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_FLOAT, GL_TRUE, 0, colors);
glDrawArrays(GL_TRIANGLE_FAN, 0, (GLsizei)nVertices);
}
@end
#import "TestScene.h"
#import "cocos2d.h"
#import "SoftBubble.h"
@implementation TestScene
- (instancetype)init
{
self = [super init];
if (self) {
CCNode *background = [CCNodeColor nodeWithColor:[CCColor whiteColor]];
[self addChild:background];
CCPhysicsNode *physics = [CCPhysicsNode node];
physics.gravity = ccp(0, -50);
physics.physicsBody = [CCPhysicsBody bodyWithPolylineFromRect:CGRectMake(0, 0, self.contentSize.width, self.contentSize.height) cornerRadius:0];
// physics.debugDraw = YES;
[self addChild:physics];
CCNode *bubble = [SoftBubble spriteWithImageNamed:@"bubble.png"];
bubble.position = ccp(160, 220);
[physics addChild:bubble];
}
return self;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment