Last active
September 4, 2024 23:40
-
-
Save pontusarmini/9ef352b6e91958a165e1 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).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SoftBubble.h | |
// | |
// | |
// Created by Pontus Armini on 2015-04-12. | |
// | |
// | |
#import "CCSprite.h" | |
@interface SoftBubble2 : CCSprite | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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