1 /* Copyright (c) 2013 Scott Lembcke and Howling Moon Software
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 #import "ObjectiveChipmunk/ObjectiveChipmunk.h"
24 @interface ChipmunkSpace(DoubleDispatch)
26 - (ChipmunkBody *)addBody:(ChipmunkBody *)obj;
27 - (ChipmunkBody *)removeBody:(ChipmunkBody *)obj;
31 @implementation ChipmunkBody {
36 // MARK: Integration Helpers
38 -(void)updateVelocity:(cpFloat)dt gravity:(cpVect)gravity damping:(cpFloat)damping
40 cpBodyUpdateVelocity(&_body, gravity, damping, dt);
43 -(void)updatePosition:(cpFloat)dt
45 cpBodyUpdatePosition(&_body, dt);
50 (cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
52 [(ChipmunkBody *)body->userData updateVelocity:dt gravity:gravity damping:damping];
57 (cpBody *body, cpFloat dt)
59 [(ChipmunkBody *)body->userData updatePosition:dt];
62 // Check if the method was overridden.
63 // No reason to add the extra method overhead if it's not needed.
64 -(BOOL)methodIsOverriden:(SEL)selector
66 return ([self methodForSelector:selector] != [[ChipmunkBody class] instanceMethodForSelector:selector]);
71 +(ChipmunkBody *)bodyFromCPBody:(cpBody *)body
73 ChipmunkBody *obj = body->userData;
74 cpAssertHard([obj isKindOfClass:[ChipmunkBody class]], "'body->data' is not a pointer to a ChipmunkBody object.");
79 + (id)bodyWithMass:(cpFloat)mass andMoment:(cpFloat)moment
81 return [[[self alloc] initWithMass:mass andMoment:moment] autorelease];
86 ChipmunkBody *body = [[self alloc] initWithMass:0.0f andMoment:0.0f];
87 body.type = CP_BODY_TYPE_STATIC;
89 return [body autorelease];
94 ChipmunkBody *body = [[self alloc] initWithMass:0.0f andMoment:0.0f];
95 body.type = CP_BODY_TYPE_KINEMATIC;
97 return [body autorelease];
100 - (id)initWithMass:(cpFloat)mass andMoment:(cpFloat)moment
102 if((self = [super init])){
103 cpBodyInit(&_body, mass, moment);
104 _body.userData = self;
106 // Setup integration callbacks if necessary.
107 if([self methodIsOverriden:@selector(updateVelocity:gravity:damping:)]){
108 _body.velocity_func = VelocityFunction;
111 if([self methodIsOverriden:@selector(updatePosition:)]){
112 _body.position_func = PositionFunction;
121 cpBodyDestroy(&_body);
125 - (cpTransform)transform {return _body.transform;}
126 - (cpBody *)body {return &_body;}
129 @synthesize userData = _userData;
132 #define getter(type, lower, upper) \
133 - (type)lower {return cpBodyGet##upper(&_body);}
134 #define setter(type, lower, upper) \
135 - (void)set##upper:(type)value {cpBodySet##upper(&_body, value);};
136 #define both(type, lower, upper) \
137 getter(type, lower, upper) \
138 setter(type, lower, upper)
141 both(cpBodyType, type, Type)
142 both(cpFloat, mass, Mass)
143 both(cpFloat, moment, Moment)
144 both(cpVect, centerOfGravity, CenterOfGravity)
145 both(cpVect, position, Position)
146 both(cpVect, velocity, Velocity)
147 both(cpVect, force, Force)
148 both(cpFloat, angle, Angle)
149 both(cpFloat, angularVelocity, AngularVelocity)
150 both(cpFloat, torque, Torque)
152 -(ChipmunkSpace *)space {
153 cpSpace *space = cpBodyGetSpace(&_body);
154 return (ChipmunkSpace *)(space ? cpSpaceGetUserData(space) : nil);
157 - (cpFloat)kineticEnergy {return cpBodyKineticEnergy(&_body);}
159 - (cpVect)localToWorld:(cpVect)v {return cpBodyLocalToWorld(&_body, v);}
160 - (cpVect)worldToLocal:(cpVect)v {return cpBodyWorldToLocal(&_body, v);}
162 - (cpVect)velocityAtLocalPoint:(cpVect)p {return cpBodyGetVelocityAtLocalPoint(&_body, p);}
163 - (cpVect)velocityAtWorldPoint:(cpVect)p {return cpBodyGetVelocityAtWorldPoint(&_body, p);}
165 - (void)applyForce:(cpVect)force atLocalPoint:(cpVect)point {cpBodyApplyForceAtLocalPoint(&_body, force, point);}
166 - (void)applyForce:(cpVect)force atWorldPoint:(cpVect)point {cpBodyApplyForceAtWorldPoint(&_body, force, point);}
167 - (void)applyImpulse:(cpVect)impulse atLocalPoint:(cpVect)point {cpBodyApplyImpulseAtLocalPoint(&_body, impulse, point);}
168 - (void)applyImpulse:(cpVect)impulse atWorldPoint:(cpVect)point {cpBodyApplyImpulseAtWorldPoint(&_body, impulse, point);}
170 - (bool)isSleeping {return cpBodyIsSleeping(&_body);}
172 - (void)activate {cpBodyActivate(&_body);}
173 - (void)activateStatic:(ChipmunkShape *)filter {cpBodyActivateStatic(&_body, filter.shape);}
174 - (void)sleepWithGroup:(ChipmunkBody *)group {cpBodySleepWithGroup(&_body, group.body);}
175 - (void)sleep {cpBodySleep(&_body);}
177 - (NSArray *)chipmunkObjects {return [NSArray arrayWithObject:self];}
178 - (void)addToSpace:(ChipmunkSpace *)space {[space addBody:self];}
179 - (void)removeFromSpace:(ChipmunkSpace *)space {[space removeBody:self];}
181 static void PushShape(cpBody *ignored, cpShape *shape, NSMutableArray *arr){[arr addObject:shape->userData];}
184 NSMutableArray *arr = [NSMutableArray array];
185 cpBodyEachShape(&_body, (cpBodyShapeIteratorFunc)PushShape, arr);
190 static void PushConstraint(cpBody *ignored, cpConstraint *constraint, NSMutableArray *arr){[arr addObject:constraint->userData];}
191 - (NSArray *)constraints
193 NSMutableArray *arr = [NSMutableArray array];
194 cpBodyEachConstraint(&_body, (cpBodyConstraintIteratorFunc)PushConstraint, arr);
199 static void CallArbiterBlock(cpBody *body, cpArbiter *arbiter, ChipmunkBodyArbiterIteratorBlock block){block(arbiter);}
200 - (void)eachArbiter:(ChipmunkBodyArbiterIteratorBlock)block
202 cpBodyEachArbiter(&_body, (cpBodyArbiterIteratorFunc)CallArbiterBlock, block);