GB2ShapeCache Shape Scale? (Physics Editor) [Box2D] - ios

There is a class associated with the program Physics Editor called GB2ShapeCache that loads shapes that I make in the program. I noticed that it is not currently possible to change the scale of the shapes on the fly so I would like to be able to scale the fixtures for the shapes that I made in Physics Editor. Now the scale of my CCSprite in my app can be random so currently in the addShapesWithFile method, I do this for polygons:
vertices[vindex].x = (offset.x * sprite.scaleX) / ptmRatio_;
vertices[vindex].y = (offset.y * sprite.scaleY) / ptmRatio_;
and this for circles:
circleShape->m_radius = ([[circleData objectForKey:#"radius"] floatValue] / ptmRatio_) *sprite.scale;
I also changed the method so that I can pass in my sprite so I can get the scale to:
-(void) addShapesWithFile:(NSString*)plist forSprite:(CCSprite*)sprite
so that I can pass in my sprite so I can get the scale.
HOWEVER, I find this to be inefficient because I should not have to reload ALL my shapes in my plist since they are already added.
So is there any way to do what I am doing now but in the addFixturesToBody method? This way I do not re-create the already added plist shapes and I only scale the fixtures when it is ready to be added to my body.
If anyone needs to see more code or needs more info, feel free to ask. I know this issue must be simple!!!
Thanks!

I would recommend implementing it in the addFixturesToBody method.
(see https://github.com/AndreasLoew/GBox2D/blob/master/GBox2D/GB2ShapeCache.mm)
Try this method below, this should scale the shapes accordingly to the sprite's they are for. Just pass in your CCSprite and this method will handle the rest.
- (void)addFixturesToBody:(b2Body*)body forShapeName:(NSString*)shape forSprite:(CCSprite*)sprite {
BodyDef *so = [shapeObjects_ objectForKey:shape];
assert(so);
FixtureDef *fix = so->fixtures;
if ((sprite.scaleX == 1.0f) && (sprite.scaleY == 1.0f)) {
// simple case - so do not waste any energy on this
while(fix) {
body->CreateFixture(&fix->fixture);
fix = fix->next;
}
} else {
b2Vec2 vertices[b2_maxPolygonVertices];
while(fix) {
// make local copy of the fixture def
b2FixtureDef fix2 = fix->fixture;
// get the shape
const b2Shape *s = fix2.shape;
// clone & scale polygon
const b2PolygonShape *p = dynamic_cast<const b2PolygonShape*>(s);
if(p)
{
b2PolygonShape p2;
for(int i=0; i<p->m_vertexCount; i++)
{
vertices[i].x = p->m_vertices[i].x * sprite.scaleX;
vertices[i].y = p->m_vertices[i].y * sprite.scaleY;
}
p2.Set(vertices, p->m_vertexCount);
fix2.shape = &p2;
}
// clone & scale circle
const b2CircleShape *c = dynamic_cast<const b2CircleShape *>(s);
if(c) {
b2CircleShape c2;
c2.m_radius = c->m_radius * sprite.scale;
c2.m_p.x = c->m_p.x * sprite.scaleX;
c2.m_p.y = c->m_p.y * sprite.scaleY;
fix2.shape = &c2;
}
// add to body
body->CreateFixture(&fix2);
fix = fix->next;
}
}
}

Related

(iOS) Accelerometer Graph (convert g-force to +/- 128) granularity

I am using this Accelerometer graph from Apple and trying to convert their G-force code to calculate +/- 128.
The following image shows that the x, y, z values in the labels do not match the output on the graph: (Note that addX:y:z values are what is shown in the labels above the graph)
ViewController
The x, y, z values are received from a bluetooth peripheral, then converted using:
// Updates LABELS
- (void)didReceiveRawAcceleromaterDataWithX:(NSInteger)x Y:(NSInteger)y Z:(NSInteger)z
{
dispatch_async(dispatch_get_main_queue(), ^{
_labelAccel.text = [NSString stringWithFormat:#"x:%li y:%li z:%li", (long)x, (long)y, (long)z];
});
}
// Updates GRAPHS
- (void)didReceiveAcceleromaterDataWithX:(NSInteger)x Y:(NSInteger)y Z:(NSInteger)z
{
dispatch_async(dispatch_get_main_queue(), ^{
float xx = ((float)x) / 8192;
float yy = ((float)y) / 8192;
float zz = ((float)z) / 8192;
[_xGraph addX:xx y:0 z:0];
[_yGraph addX:0 y:yy z:0];
[_zGraph addX:0 y:0 z:zz];
});
}
GraphView
- (BOOL)addX:(UIAccelerationValue)x y:(UIAccelerationValue)y z:(UIAccelerationValue)z
{
// If this segment is not full, then we add a new acceleration value to the history.
if (index > 0)
{
// First decrement, both to get to a zero-based index and to flag one fewer position left
--index;
xhistory[index] = x;
yhistory[index] = y;
zhistory[index] = z;
// And inform Core Animation to redraw the layer.
[layer setNeedsDisplay];
}
// And return if we are now full or not (really just avoids needing to call isFull after adding a value).
return index == 0;
}
- (void)drawLayer:(CALayer*)l inContext:(CGContextRef)context
{
// Fill in the background
CGContextSetFillColorWithColor(context, kUIColorLightGray(1.f).CGColor);
CGContextFillRect(context, layer.bounds);
// Draw the grid lines
DrawGridlines(context, 0.0, 32.0);
// Draw the graph
CGPoint lines[64];
int i;
float _granularity = 16.f; // 16
NSInteger _granualCount = 32; // 32
// X
for (i = 0; i < _granualCount; ++i)
{
lines[i*2].x = i;
lines[i*2+1].x = i + 1;
lines[i*2].y = xhistory[i] * _granularity;
lines[i*2+1].y = xhistory[i+1] * _granularity;
}
CGContextSetStrokeColorWithColor(context, _xColor.CGColor);
CGContextStrokeLineSegments(context, lines, 64);
// Y
for (i = 0; i < _granualCount; ++i)
{
lines[i*2].y = yhistory[i] * _granularity;
lines[i*2+1].y = yhistory[i+1] * _granularity;
}
CGContextSetStrokeColorWithColor(context, _yColor.CGColor);
CGContextStrokeLineSegments(context, lines, 64);
// Z
for (i = 0; i < _granualCount; ++i)
{
lines[i*2].y = zhistory[i] * _granularity;
lines[i*2+1].y = zhistory[i+1] * _granularity;
}
CGContextSetStrokeColorWithColor(context, _zColor.CGColor);
CGContextStrokeLineSegments(context, lines, 64);
}
How can I calculate the above code to show the correct accelerometer values on the graph with precision?
I post this as an aswer not a comment, because I have not enough reputation, but what I'll write might be enough to send you in the right direction, that it even may count as an answer...
Your question still doesn't include what is really important. I assume the calculation of the xx/yy/zz is no problem. Although I have no idea what the 8192 is supposed to mean.
I guess the preblem is in the part where you map your values to pixel coordinates...
the lines[] contains your values in a range of 1/8192th of the values in the label. so your x value of -2 should be at a pixel position of -0.0000something, so slightly(far less than 1 Pixel) above the view... Because you see the line a lot further down there must be some translation in place (not shown in your code)
The second part that is important but not shown is DrawGridlines. Probably in there is a different approach to map the values to pixel-coordinates...
Use the debugger to check what pixel-coordinates you get when draw your +127-line and what you get if you insert the value of +127 in your history-array
And some Ideas for improvements when reading your code:
1.)Put the graph in it's own class that draws one graph(and has only one history. Somehow you seem to have that partially already (otherwise I cannot figure out your _xGraph/_yGraph/_zGraph) But on the other hand you draw all 3 values in one drawLayer??? Currently you seem to have 3*3 history buffers of which 3*2 are filled with zeros...
2.) use one place where you do the calculation of Y that you use both for drawing the grid and drawing the lines...
3.) use CGContextMoveToPoint(); + CGContextAddLineToPoint(); instead of copying into lines[] with these ugly 2*i+1 indecies...

How to know when all physics bodies have stopped moving in Cocos2d V3.0 with Chipmunk

The only way I can think to do it is to check velocities for all physics bodies during every collisions.
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair piece:(CCNode *)pieceA piece:(CCNode *)pieceB{
float x = 0;
float y = 0;
for (int i = 0; i < [[_physicsWorld children] count]; i++) {
x = x + [[[_physicsWorld children][i] physicsBody] velocity].x;
y = y + [[[_physicsWorld children][i] physicsBody] velocity].y;
}
if ( x == 0 && y == 0 ) {
NSLog(#"stopped");
}
return YES;
}
This logs “stopped” multiple times when the scene first loads, then doesn’t log “stopped” again, even after physics bodies have clearly started moving and colliding and then come to a stop.
Ideally I'd like a delegate method that would notify me when all physics bodies have stopped moving, but I can't seem to find one.
FYI: I'm using the standard Chipmunk physics engine that's baked into Cocos2d V3.0
Chipmunk has a internal mechanism, which can, if activated, automatically deactivate physics bodies. My approach (I am using cocos2dx 3.11.1 and not -obj version with chipmunk 7.0.1) is:
activate the chipmunk idle mechanism (0.5 second - meaning, if an object is not moving for longer than 0.5 second it will be deactivated):
cpSpaceSetSleepTimeThreshold(space, 0.5f);
You do not need to use
cpSpaceSetIdleSpeedThreshold(space, <speed>);
because chipmunk calculates the threshold speed for you (according the gravitation used).
use this code for determination if all objects are not moving (static and kinetic bodies never sleep):
bool isAnyPhysicsBodyMoving(){
int i = 0; bool isMoving = false;
const Vector<PhysicsBody*>& bodies = getPhysicsWorld()->getAllBodies();
while( i < bodies.size() && !isMoving){
PhysicsBody *body = bodies.at(i);
isMoving = cpBodyGetType(body->getCPBody()) == CP_BODY_TYPE_DYNAMIC
&& !body->isResting();
i++;
}
return isMoving;
}
use static (and not kinetic) body for walls, in order to let objects sleep:
// wall
Size visibleSize = Director::getInstance()->getWinSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
float border = 10.0f;
Size wallBodySize = Size(visibleSize.width+2*border, visibleSize.height+2*border);
PhysicsBody *wallBody = PhysicsBody::createEdgeBox(wallBodySize, PhysicsMaterial(1.0f, 1.0f, 0.5f), border);
Node* wall = Node::create();
wall->addComponent(wallBody);
wall->setAnchorPoint(Vec2(0.5f, 0.5f));
wall->setPosition(Point(visibleSize.width/2+origin.x, visibleSize.height/2+origin.y));
cpVect tt;
tt.x = wall->getPosition().x; tt.y = wall->getPosition().y;
//set position manually and BEFORE adding the object into the space
cpBodySetPosition(wallBody->getCPBody(), tt);
cpBodySetType(wallBody->getCPBody(), CP_BODY_TYPE_STATIC);
addChild(wall);
Any dynamic body connected to a kinetic body (for example laying on) will never sleep.
test it with DEBUG activated
getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
the boxes (their content) must become grey (=sleeping) and not red (=active):
In order to let it work, I have:
added an access method (to get cpSpace) in CCPhysicsWorld.h:
inline cpSpace* getSpace() const { return _cpSpace; }
Fix call of
cpBodySetTorque(body, 0.0f);`
in CCPhysicsBody.cpp to
if (body->t != 0.0f){
cpBodySetTorque(body, 0.0f);
}
Fix call of
cpBodySetPosition(_cpBody, tt);`
in CCPhysicsBody.cpp to
if (!cpveql(tt, cpBodyGetPosition(_cpBody))){
cpBodySetPosition(_cpBody, tt);
}
Steps 2. and 3. are necessary to avoid setting of the same physics body properties, which wake up a sleeping body.
The advantage of this approach is, that the chipmunk does not make any calculations for such physical bodies - saving CPU and battery.
I found something that works.
tl;dr
The basic idea is to keep track of the positions of the sprites myself, and then periodically check them to see if any of them have moved since they were last checked.
Longer version
I created a subclass of CCNode with the class name Piece.
These are my objects that are added to the physics world.
#implementation Piece {
float _previousX;
float _previousY;
}
-(void)updatePreviousScreenXandY{
_previousX = self.position.x;
_previousY = self.position.y;
}
-(BOOL)hasntMoved{
float currentX = self.position.x;
float currentY = self.position.y;
if ( currentX == _previousX && currentY == _previousY ) {
return TRUE;
}else{
return FALSE;
}
}
This is in my CCNode that acts as the game scene
-(void)doStuffAfterPiecesStopMoving:(NSTimer*)timer{
BOOL noPiecesHaveMoved = TRUE;
for (int i = 0; i < [[_physicsWorld children] count]; i++) {
if ( [[_physicsWorld children][i] hasntMoved] == FALSE ) {
noPiecesHaveMoved = FALSE;
break;
}
}
if ( noPiecesHaveMoved ) {
[timer invalidate];
NSLog(“Pieces have stopped moving”);
}else{
NSLog(“Pieces are still moving”);
[self updateAllPreviousPiecePositions];
}
}
-(void)updateAllPreviousPiecePositions{
for (int i=0; i < [[_physicsWorld children] count]; i++) {
Piece *piece = (Piece*)[_physicsWorld children][i];
[piece updatePreviousScreenXandY];
}
}
All I have to do is
[NSTimer scheduledTimerWithTimeInterval:TIME_BETWEEN_CHECKS
target:_gamePlay
selector:#selector(doStuffAfterPiecesStopMoving:)
userInfo:nil
repeats:YES];
and it’ll run whatever code I want after all Piece nodes have stopped moving.
The key to getting it to work well is to get the values for the Chipmunk space’s sleepTimeThreshold and the timer above’s time as low as possible.
My experimenting suggests the following settings work okay, but anything lower will cause problems (i.e. collisions not taking place properly):
sleepTimeThreshold = 0.15
my timer = 0.05
If anyone has a different/better solution or improvements to the above code, please post.

Rectangle and Circle collision detection

I am trying to do collision detection between a rectangle and a circle. I came up with this method:
-(BOOL) isCollidingRect:(CCSprite *) spriteOne WithSphere:(CCSprite *) spriteTwo {
float diff = ccpDistance(spriteOne.position, spriteTwo.position);
float obj1Radii = [spriteOne boundingBox].size.width/2;
float obj2Radii = [spriteTwo boundingBox].size.width/2;
if (diff < obj1Radii + obj2Radii) {
return YES;
} else {
return NO;
}
}
and this is how I check it:
if ([self isCollidingRect:player WithSphere:blocker] == true) {
[self playerdeathstart];
}
This seems to work properly on the side of the rectangle but it doesn't above or below it. On the top and bottom, the collision occurs too early.
Is there a way I can get this collision to detected properly? Thank you for your help.
You can use CGRectIntersectsRect to achieve this.
-(BOOL) isCollidingRect:(CCSprite *) spriteOne WithSphere:(CCSprite *) spriteTwo {
return CGRectIntersectsRect([spriteOne boundingBox],[spriteTwo boundingBox]);
}
It is not pixel perfect but as i understand that is not necessary in this case.
This is not a solution for those who use Cocos2d-ObjC, but will help for Cocos2d-x devs (for instance, personally I found this topic because was searching for the same for my c++ game).
Cocos2d-x has method "intersectsCircle" for Rect class.
Here is how I solved in my c++ project almost the same problem as one described by you:
bool ObstacleEntity::hasCollisionAgainst(cocos2d::Sprite *spr)
{
cocos2d::Rect rect = cocos2d::Rect( spr->getPositionX(), spr->getPositionY(), spr->getBoundingBox().size.width, spr->getBoundingBox().size.height);
float rw = this->getBoundingBox().size.width / 2;
float rh = this->getBoundingBox().size.height / 2;
float radius = ( rw > rh ) ? rw : rh;
cocos2d::Vec2 center( this->getPositionX() + rw, this->getPositionY() + rh );
return rect.intersectsCircle( center, radius );
}
Passed Sprite here is rectangle, while ObstacleEntity always is almost ideally round.
Note that anchor points for all entities are set to lower left corner in my case.

Starling + Box2d - Collision not precise

I create stage walls and a box inside on my mobile app using starling + as3.
Ok, now when I test the app the box falls but it does not match the walls, as if there
was an offset:
https://www.dropbox.com/s/hd4ehnfthh0ucfm/box.png
Here is how I created the boxes (walls and the box).
It seems like there is an offset hidden, what do you think?
public function createBox(x:Number, y:Number, width:Number, height:Number, rotation:Number = 0, bodyType:uint = 0):void {
/// Vars used to create bodies
var body:b2Body;
var boxShape:b2PolygonShape;
var circleShape:b2CircleShape;
var fixtureDef:b2FixtureDef = new b2FixtureDef();
fixtureDef.shape = boxShape;
fixtureDef.friction = 0.3;
// static bodies require zero density
fixtureDef.density = 0;
var quad:Quad;
bodyDef = new b2BodyDef();
bodyDef.type = bodyType;
bodyDef.position.x = x / WORLD_SCALE;
bodyDef.position.y = y / WORLD_SCALE;
// Box
boxShape = new b2PolygonShape();
boxShape.SetAsBox(width / WORLD_SCALE, height / WORLD_SCALE);
fixtureDef.shape = boxShape;
fixtureDef.density = 0;
fixtureDef.friction = 0.5;
fixtureDef.restitution = 0.2;
// create the quads
quad = new Quad(width, height, Math.random() * 0xFFFFFF);
quad.pivotX = 0;
quad.pivotY = 0;
// this is the key line, we pass as a userData the starling.display.Quad
bodyDef.userData = quad;
//
body = m_world.CreateBody(bodyDef);
body.CreateFixture(fixtureDef);
body.SetAngle(rotation * (Math.PI / 180));
_clipPhysique.addChild(bodyDef.userData);
}
The SetAsBox method takes half width and half height as its parameters. I'm guessing your graphics don't match your box2d bodies. So either you will need to make your graphics twice as big or multiply your SetAsBox params by 0.5. Also the body pivot will be in the center of it, so offset your movieclip accordingly depending on its pivot position.
Note that box2d has a debugrenderer which can outline your bodies for you to see what's going on.

How to create several UIButtons along a path/BezierCurve?

How can I create objects along a path/BezierCurve? In other words, how can I create several UIButtons along a given path, with a given interval along that same path?
I have seen dozens of questions about moving objects. But I need a solution to actually create them.
I would like to go along the path and create an object for every X points/distance. Like this:
....#....#....#....#....
In this case, for every 4 points, get the position, and create a UIButton there.
iOS doesn't have a public API that directly gives you points spaced along a path. But there is a roundabout way to do it. Suppose you want points along the path spaced a distance of X apart.
First, create a CGPathRef containing your path. (You can construct a UIBezierPath if you prefer and then gets its CGPath property.)
Then, call CGPathCreateCopyByDashingPath, using a dash pattern of { X, X }. For example:
static CGFloat const kSpace = 10;
CGPathRef dashedPath = CGPathCreateCopyByDashingPath(path, NULL, 0,
(CGFloat const []){ kSpace, kSpace }, 2);
This returns a new path containing multiple subpaths. Each subpath is a length X segment of the original path, and is separated from its neighboring subpaths by a distance of X along the original path. Thus the endpoints of the subpaths are spaced along the original path at an interval of length X.
So, finally, enumerate the dashed path using CGPathApply, picking the endpoints and creating buttons there. First, you'll want to wrap it in a function that takes a block:
static void applyBlockToPathElement(void *info, const CGPathElement *element) {
void (^block)(const CGPathElement *) = (__bridge void (^)(const CGPathElement *))(info);
block(element);
}
void MyCGPathApplyBlock(CGPathRef path, void (^block)(const CGPathElement *element)) {
CGPathApply(path, (__bridge void *)(block), applyBlockToPathElement);
}
Then you can apply a block that finds the each subpath endpoint and creates a button there. Assuming you have a method named createButtonAtPoint:, something like this should work:
__block BOOL isInSubpath = NO;
__block CGPoint subpathStart = CGPointZero;
__block CGPoint currentPoint = CGPointZero;
MyCGPathApplyBlock(dashedPath, ^(const CGPathElement *element) {
switch (element->type) {
case kCGPathElementMoveToPoint:
if (isInSubpath) {
[self createButtonAtPoint:currentPoint];
isInSubpath = NO;
}
currentPoint = element->points[0];
break;
case kCGPathElementCloseSubpath:
// This should not appear in a dashed path.
break;
case kCGPathElementAddLineToPoint:
case kCGPathElementAddQuadCurveToPoint:
case kCGPathElementAddCurveToPoint:
if (!isInSubpath) {
[self createButtonAtPoint:currentPoint];
isInSubpath = YES;
}
int pointIndex =
element->type == kCGPathElementAddLineToPoint ? 0
: element->type == kCGPathElementAddQuadCurveToPoint ? 1
: /* element->type == kCGPathElementAddCurveToPoint ? */ 2;
currentPoint = element->points[pointIndex];
break;
}
});
Have you solved your problem yet? if no, see this if it could help
//if the interval is kown as float, suggesting it named padding
//then you can
for(i=0;i<numOfPaddings;i++){
//create a button
UIButton *aButton = [UIButton buttonWithType:UIButtonRoundRect/*I forgot how to spell,but it does not metter*/];
//Set your button's position base on padding
[aButton setFrame:CGRectMake(padding+padding*i,20,50,20)];
}

Resources