Skip to content

Instantly share code, notes, and snippets.

@sergiomtzlosa
Forked from slembcke/rope.m
Created April 26, 2012 06:48
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 sergiomtzlosa/2496886 to your computer and use it in GitHub Desktop.
Save sergiomtzlosa/2496886 to your computer and use it in GitHub Desktop.
/////// RopeNode.h
#import "cocos2d.h"
#import "ObjectiveChipmunk.h"
struct RopeNodeParticle;
@interface RopeNode : CCNode {
ChipmunkBody *_body1, *_body2;
cpVect _offset1, _offset2;
int _count;
cpFloat _segLength;
int _iterations;
cpFloat _width;
ccColor4B _color;
cpFloat _damping;
cpVect _gravity;
struct RopeNodeParticle *_particles;
}
@property(assign) cpFloat length;
@property(assign) cpFloat width;
@property(assign) ccColor4B color;
@property(assign) cpFloat damping;
@property(assign) cpVect gravity;
@property(assign) int iterations;
- (id)initWithLength:(cpFloat)length segments:(int)count
body1:(ChipmunkBody *)body1 body2:(ChipmunkBody *)body2
offset1:(cpVect)offset1 offset2:(cpVect)offset2;
- (void)step;
@end
/////// RopeNode.m
#import "RopeNode.h"
typedef struct RopeNodeParticle {
cpVect pos, prev;
} Particle;
@implementation RopeNode
@synthesize gravity = _gravity, iterations = _iterations, damping = _damping, width = _width, color = _color;
- (id)initWithLength:(cpFloat)length segments:(int)count
body1:(ChipmunkBody *)body1 body2:(ChipmunkBody *)body2
offset1:(cpVect)offset1 offset2:(cpVect)offset2;
{
if((self = [super init])){
_body1 = [body1 retain];
_body2 = [body2 retain];
_offset1 = offset1;
_offset2 = offset2;
_count = count;
_iterations = 5;
self.length = length;
_width = 1.0f;
_color = ccc4(255, 255, 255, 255);
cpVect start = [_body1 local2world:offset1];
cpVect end = [_body2 local2world:offset2];
_particles = calloc(count + 1, sizeof(Particle));
for(int i=0; i<=count; i++){
cpVect p = cpvlerp(start, end, (cpFloat)i/(cpFloat)count);
_particles[i] = (Particle){p, p};
}
}
return self;
}
- (void)dealloc {
[_body1 release];
[_body2 release];
free(_particles);
[super dealloc];
}
-(void)setLength:(cpFloat)length {
_segLength = length/_count;
}
-(cpFloat)length {
return _segLength;
}
static inline Particle
stepParticle(Particle p, cpVect g, cpFloat damping)
{
cpVect pos = p.pos;
cpVect vel = cpvmult(cpvsub(pos, p.prev), damping);
return (Particle){cpvadd(cpvadd(pos, vel), g), pos};
}
static inline void
contract(Particle *particles, int i, int j, cpFloat dSQ, cpFloat ratio)
{
cpVect v1 = particles[i].pos;
cpVect v2 = particles[j].pos;
cpVect delta = cpvsub(v2, v1);
if(cpvlengthsq(delta) < dSQ) return;
cpFloat diff = 0.5f - dSQ/(cpvlengthsq(delta) + dSQ);
particles[i].pos = cpvadd(v1, cpvmult(delta, diff*ratio));
particles[j].pos = cpvadd(v2, cpvmult(delta, diff*(ratio - 1.0)));
}
- (void)step;
{
int count = _count;
Particle *particles = _particles;
cpVect g = _gravity;
cpFloat damping = _damping;
for(int i=1; i<count; i++) particles[i] = stepParticle(particles[i], g, damping);
particles[0].pos = [_body1 local2world:_offset1];
particles[count].pos = [_body2 local2world:_offset2];
cpFloat dSQ = _segLength*_segLength;
for(int iteration=0; iteration<_iterations; iteration++){
contract(particles, 0, 1, dSQ, 0.0f);
for(int i=2; i<count; i++) contract(particles, i-1, i, dSQ, 0.5f);
contract(particles, count-1, count, dSQ, 1.0f);
}
}
static void
generateVertexes(Particle *particles, cpVect *verts, int count, cpFloat width)
{
cpVect v0 = particles[0].pos;
cpVect t0 = cpvperp(cpvnormalize_safe(cpvsub(particles[1].pos, v0)));
verts[0] = cpvadd(v0, cpvmult(t0, width));
verts[1] = cpvadd(v0, cpvmult(t0, -width));
for(int i=1; i<count-1; i++){
cpVect v1 = particles[i].pos;
cpVect t1 = cpvperp(cpvnormalize_safe(cpvsub(v1, v0)));
cpVect t = cpvmult(cpvnormalize_safe(cpvlerp(t0, t1, 0.5f)), width);
verts[2*i+0] = cpvadd(v1, t);
verts[2*i+1] = cpvadd(v1, cpvneg(t));
v0 = v1, t0 = t1;
}
cpVect v1 = particles[count-1].pos;
cpVect t1 = cpvperp(cpvnormalize_safe(cpvsub(v1, particles[count-2].pos)));
verts[2*count-2] = cpvadd(v1, cpvmult(t1, width));
verts[2*count-1] = cpvadd(v1, cpvmult(t1, -width));
}
- (void)draw {
int count = _count + 1;
cpVect verts[count*2];
generateVertexes(_particles, verts, count, _width);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// glBindTexture(GL_TEXTURE_2D, textureAtlas.name);
glDisable(GL_TEXTURE_2D);
glColor4ub(_color.r, _color.g, _color.b, _color.a);
glVertexPointer(2, GL_FLOAT, 0, verts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, count*2);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment