Skip to content

Instantly share code, notes, and snippets.

@castrokingjames
Forked from pontusarmini/Soft body CCSprite
Last active August 29, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save castrokingjames/f5e3d935188d3cf84c34 to your computer and use it in GitHub Desktop.
Save castrokingjames/f5e3d935188d3cf84c34 to your computer and use it in GitHub Desktop.
Soft body CCSprite originally created by Sébastien Dabet (Gist: https://gist.github.com/sdabet/08a6f41415c5e3b8be0f and tutorial: http://2sa-studio.blogspot.se/2014/05/soft-bodies-with-cocos2d-v3.html) updated for the new rendering engine (Cocos2d-SpriteBuilder >3.1).
//
// SoftBubble.h
//
//
// Created by Pontus Armini on 2015-04-12.
//
//
#import "CCSprite.h"
@interface SoftBubble2 : CCSprite
@end
//
// SoftBubble2.m
//
//
// Created by Pontus Armini on 2015-04-12.
//
//
#import "SoftBubble2.h"
#import "cocos2d.h"
#import "CCTexture_Private.h"
#import "CCSprite_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 SoftBubble2 {
ccVertex2F vertices[NUM_SEGMENTS+2];
ccTex2F texCoords[NUM_SEGMENTS+2];
ccColor4F texColor;
float bubbleRadius;
}
- (id)initWithImageNamed:(NSString*)imageName;
{
self = [super initWithImageNamed:imageName];
if (self) {
// Bubble radius is the the texture half-width
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];
}
//Setting up the color. This will render the original colors of the texture
texColor = ccc4f(1.0, 1.0, 1.0, 1.0);
//Setting up the vertices
[self updateVertices];
//Setting up the texture coordinates
[self setUpTexCoords];
}
return self;
}
-(void)updateVertices
{
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];
}
-(void)setUpTexCoords
{
float deltaAngle = (2.f * M_PI) / NUM_SEGMENTS;
texCoords[0] = (ccTex2F){0.5f, 0.5f};
for (int i = 0; i < NUM_SEGMENTS; i++) {
GLfloat coordAngle = M_PI + (deltaAngle * i);
texCoords[i+1] = (ccTex2F){0.5 + cosf(coordAngle)*0.5, 0.5 + sinf(coordAngle)*0.5};
}
texCoords[NUM_SEGMENTS+1] = texCoords[1];
}
// Helper taken from CCMotionStreak (https://github.com/cocos2d/cocos2d-spritebuilder/blob/v3.4/cocos2d/CCMotionStreak.m)
static inline CCVertex
MakeVertex(ccVertex2F v, ccTex2F texCoord, ccColor4F color, GLKMatrix4 transform)
{
return (CCVertex){
GLKMatrix4MultiplyVector4(transform, GLKVector4Make(v.x, v.y, 0.0f, 1.0f)),
GLKVector2Make(texCoord.u, texCoord.v), GLKVector2Make(0.0f, 0.0f),
GLKVector4Make(color.r, color.g, color.b, color.a)
};
}
// Map the texture on the physics bodies with a triangle fan
-(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform {
[self updateVertices];
//Create buffer
CCRenderBuffer buffer = [renderer enqueueTriangles:NUM_SEGMENTS andVertexes:NUM_SEGMENTS+2 withState:self.renderState globalSortOrder:0];
//Output Vertices
for (int i = 0; i < NUM_SEGMENTS+2; i++)
{
CCRenderBufferSetVertex(buffer, i, MakeVertex(vertices[i], texCoords[i], texColor, *transform));
}
//Output triangles
for (int i = 0; i < NUM_SEGMENTS; i++)
{
CCRenderBufferSetTriangle(buffer, i, 0, i+1, i+2);
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment