Created
January 23, 2011 17:55
-
-
Save slembcke/792276 to your computer and use it in GitHub Desktop.
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
/////// 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
thanks! I'm going to try your code and see it in action.