How to apply impulse on chipmunk body on a specific direction? - objective-c

i am using:
cpVect vector1=cpv(angle, 400);
[body applyForce:vector1 offset:vector1];
but this not working well as needed to put a correct angle using touch screen
below line of code used for getting angle
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for( UITouch *touch in touches )
{
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
float angleRadians = atanf((float)location.y/ (float)location.x-1);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleDegrees;
angle = angleDegrees + 30;
}
}

Thanks to you all for your precious time to give on that.
Finally i found the way to achieve impulse on a chipmunk body on a specific direction.
Now i am using below code.
**angle = angle-90; //angle from cctouchesMoved function
float magnitude=shootPower; // magnitude range between 200 to 1000
cpVect impulse = cpv((cos(angle) * magnitude) , -(sin(angle) * magnitude));
[body applyImpulse:impulse offset:cpvzero];**
// applyImpulse gives the right way for putting impulse as needed using above sin and cos theta values.

Related

Check when SKShapeNode is clicked

So I generated an SKShapeNode, and need to know when that node is clicked. I do so by calling:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:positionInScene];
if ([node.name isEqualToString:TARGET_NAME]) {
// do whatever
}
}
}
So the result I'm getting is pretty weird. Clicking the dot itself does in fact work. However, pressing anywhere on the screen that is southwest of the SKShapeNode's position will also render the above code as true.
With the SKShapeNode represented by the red dot, any UITouch in the shaded region would render my code above as true.
Here is how I am building the SKShapeNode. It may also be important to note that my application runs in landscape mode.
#define RANDOM_NUMBER(min, max) (arc4random() % (max - min) + min)
- (SKShapeNode *)makeNodeWithName:(NSString *)name color:(UIColor *)color
{
SKShapeNode *circle = [SKShapeNode new];
int maxXCoord = self.frame.size.width;
int maxYCoord = self.frame.size.height;
CGFloat x = RANDOM_NUMBER((int)TARGET_RADIUS, (int)(maxXCoord - TARGET_RADIUS));
CGFloat y = RANDOM_NUMBER((int)TARGET_RADIUS, (int)(maxYCoord - TARGET_RADIUS - 15));
circle.fillColor = color;
circle.strokeColor = color;
circle.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(x, y, TARGET_RADIUS, TARGET_RADIUS)].CGPath;
circle.name = name;
return circle;
}
Thanks for any help!
This happens because the circle node's position is at origin, and it draws the path in a rect starting at (x,y). So the node's frame is stretched to encompass everything between (0,0) to (x+TARGET_RADIUS, y+TARGET_RADIUS).
You can check this out for yourself, by visualizing the circle's frame:
SKSpriteNode *debugFrame = [SKSpriteNode spriteNodeWithColor:[NSColor yellowColor] size:circle.frame.size];
debugFrame.anchorPoint = CGPointMake(0, 0);
debugFrame.position = circle.frame.origin;
debugFrame.alpha = 0.5f;
[self addChild:test];
This reveals the actual clickable region (on OSX):
To fix your issue, try this:
circle.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-TARGET_RADIUS/2.0f, -TARGET_RADIUS/2.0f, TARGET_RADIUS, TARGET_RADIUS)].CGPath;
and add
circle.position = CGPointMake(x, y);

Radian Angle Check in Box2d Objective-C

I am creating a Car Game in Objective C with Box2D. I want to rotate the Car Wheels according to a CCSprite (Steering) Rotation.
So For this, i am successfully able to set the angle for CCSprite Steering according to touch. But when i am trying to get the Value of Steer rotation then Its not getting perfect result, although Steer is rotating perfectly. But Radian Angle value is not perfect some times. So i am not able to rotate wheels as per Steering rotation
My Code is to set the Steering Angle is as below
On Touch Begin, setting Starting angle
-(void)getAngleSteer:(UITouch *) touch
{
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
float adjacent = steering.position.x - location.x;
float opposite = steering.position.y - location.y;
self.startAngleForSteer = atan2f(adjacent, opposite);
}
On Touch Move, Moving Steering and Setting Car Angle
-(void)rotateSteer:(UITouch *) touch
{
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
float adjacent = steering.position.x - location.x;
float opposite = steering.position.y - location.y;
float angle = atan2f(adjacent, opposite);
angle = angle - self.startAngleForSteer;
steering.rotation = CC_RADIANS_TO_DEGREES(angle);
//Main issue is in below line
NSLog(#"%f %f", angle, CC_RADIANS_TO_DEGREES(angle));
if(angle > M_PI/3 || angle < -M_PI/3) return;
steering_angle = -angle;//This is for Box2D Car Angle
}
This is the Log, when moving Steer, anticlock wise
-0.127680 -7.315529
-0.212759 -12.190166
-0.329367 -18.871363
5.807306 332.734131 // Why is 5.80 cuming just after -0.32 it should be decrease.
5.721369 327.810303
5.665644 324.617462
Finally Got the answer for this. Thanks to Box2D forum (http://box2d.org/forum/viewtopic.php?f=5&t=4726)
For Objective C we have to normalize the angle like below function.
-(float) normalizeAngle:(float) angle
{
CGFloat result = (float)((int) angle % (int) (2*M_PI));
return (result) >= 0 ? (angle < M_PI) ? angle : angle - (2*M_PI) : (angle >= -M_PI) ? angle : angle + (2*M_PI);
}
And just call it before the condition check M_PI/3
steering.rotation = CC_RADIANS_TO_DEGREES(angle);
angle = [self normalizeAngle:angle];//This is where to call.
if(angle > M_PI/3 || angle < -M_PI/3) return;
steering_angle = -angle;

Need CCRenderTexture to render faster ios

I'm making a drawing app, and I'm having the users draw with CCRenderTexture. It basically keeps rendering a picture of a black circle to simulate drawing. When I move my finger slowly, it works really well since the circles come together to form a line. However, when I move my finger quickly, it ends up just being a bunch of circles that aren't connected (http://postimage.org/image/wvj3w632n/). My question is how I get the render texture to render the image faster or have it fill in the blanks for me.
Also, I'm not completely sold on this method, but it's what I've found while looking around. Feel free to suggest whatever you think would be better. I was originally using ccdrawline but it really killed my performance. Thanks!
The gaps between start point and the end points need to be sorted out. I am pasting code that might help you to resolve the situation you showed in the link.
in .h file
CCRenderTexture *target;
CCSprite* brush;
in the init method of .m file
target = [[CCRenderTexture renderTextureWithWidth:size.width height:size.height] retain];
[target setPosition:ccp(size.width/2, size.height/2)];
[self addChild:target z:1];
brush = [[CCSprite spriteWithFile:#"brush_i3.png"] retain];
add the touches method I am showing the touchesMoved code.
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint start = [touch locationInView: [touch view]];
start = [[CCDirector sharedDirector] convertToGL: start];
CGPoint end = [touch previousLocationInView:[touch view]];
end = [[CCDirector sharedDirector] convertToGL:end];
printf("\n x= %f \t y= %f",start.x,start.y);
float distance = ccpDistance(start, end);
if (distance > 1)
{
int d = (int)distance;
for (int i = 0; i < d; i++)
{
float difx = end.x - start.x;
float dify = end.y - start.y;
float delta = (float)i / distance;
[brush setPosition:ccp(start.x + (difx * delta), start.y + (dify * delta))];
[target begin];
[brush setColor:ccc3(0, 255, 0)];
brush.opacity = 5;
[brush visit];
[target end];
}
}
}
Hopefully it would work for you.
Its not that CCRenderTexture draws too slow its that the event only fires so often. You do need to fill in the gaps between the touch points you receive.
There is a great tutorial here about it which you may have already seen, http://www.learn-cocos2d.com/2011/12/how-to-use-ccrendertexture-motion-blur-screenshots-drawing-sketches/#sketching

CCTMXTiledMap touch detection is a bit off

I used the tile tutorial from www.raywenderlich.com. I set up a tile map in a landscape view and used the code from the tutorial to detect touch, like this:
CGPoint touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
And use this bit to figure which tile it is on:
CGPoint touchTilePos = [self tileCoordForPosition:touchLocation];
int tileIndex = [self tileIndexForTileCoord:(touchTilePos)];
CCSprite *touchTile = [self.background tileAt:touchTilePos];
self.player.position = [touchTile.parent convertToWorldSpace:touchTile.position];
Problem is that it's a bit off. Touch close to the left side is fairly close, but touch close to the right side is detected way off to the left. Seems like some sort of scaling issue, but the only scaling in my code is the player sprite.
Any ideas? Suggestions?
Any halp is greatly appreciated!
EDIT: here is the two methods referenced in the code:
- (CGPoint) tileCoordForPosition:(CGPoint)position
{
int x = position.x / _tileMap.tileSize.width;
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
return ccp(x, y);
}
- (int) tileIndexForTileCoord:(CGPoint)aTileCoord
{
return aTileCoord.y*(self.tileMap.mapSize.width) + aTileCoord.x;
}
UPDATE:
I simplified the code:
CGPoint touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
touchLocation = [self.background convertToNodeSpace:touchLocation];
int x = touchLocation.x / _tileMap.tileSize.width;
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - touchLocation.y) / _tileMap.tileSize.height;
CGPoint touchTilePos = ccp(x,y);
Also, i noticed that right off the start, touchLocation is off to the left, i don't think this code works correctly for my case (iPad/landscape):
CGPoint touchLocation = [touch locationInView: [touch view]];
I made a fatal mistake! I am using HEX tiles, and they overlap a bit (about 1/4). I have to account for that! And that's why the effect gets worse as i tap further to the right,
Here is the code to fix it:
int x = (touchLocation.x - tileSize.width/8) / (_tileMap.tileSize.width * (3.0/4.0)) ;
int y = 0;
if(x % 2 == 0)
{
// even
y = ((_tileMap.mapSize.height * tileSize.height) - touchLocation.y) / tileSize.height;
}
else
{
// odd
y = ((_tileMap.mapSize.height * tileSize.height) - (touchLocation.y + tileSize.height/2)) / tileSize.height;
}
CGPoint touchTilePos = ccp(x,y);
Cheers!
The tutorial code looks like it should work fine. I use code that's mathematically the same with consistent/correct results.
My only suggestion is to make doubly sure that the self object in this line:
touchLocation = [self convertToNodeSpace:touchLocation]; is the actual, immediate parent node of your TMXMap.
In my code, the CCLayer is not the immediate parent, so I end up explicitly tagging my map's parent node so I can grab it like this:
CCNode *parentNode = [self getChildByTag:kTagParentNode];
CGPoint worldPt = [parentNode convertToNodeSpace:touchLocation];

iOS Math for a turret/cannon that rotates to follow a finger

I am trying to figure out the math for rotating a UIView a certain side is always "follows" a finger when moving on the screen.
I'm almost there but I haven't had trigonometry in years and I can't figure out exactly what to do. Here is what I've got:
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
int dy = cannon.frame.origin.y - touchPoint.y;
int dx = cannon.frame.origin.x - touchPoint.x;
cannon.transform = CGAffineTransformMakeRotation(atan2(dy,dx) - 135);
}
First, thank you to everyone who took the time to answer!
I played around with it for a while, and it seems that the only problem was that I used ints for dy and dx instead of floats. I also found a nifty, quick "method" for converting degrees to radians. Here is the final, working code:
#define DEGREES_TO_RADIANS(angle) (angle / 180.0 * M_PI)
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
float dy = cannon.frame.origin.y - touchPoint.y;
float dx = cannon.frame.origin.x - touchPoint.x;
cannon.transform = CGAffineTransformMakeRotation(atan2(dy,dx) - DEGREES_TO_RADIANS(90));
}
I assume your turret initial heading is right.
Your PI constant is 3.14 (angles in radian)
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
int dy = cannon.frame.origin.y - touchPoint.y;
int dx = cannon.frame.origin.x - touchPoint.x;
float a = atan(abs(dy)/abs(dx));
if(dx>0 && dy<0) a += PI/2;
if(dx<0 && dy<0) a += PI;
if(dx<0 && dy>0) a += 3*PI/2;
cannon.transform = CGAffineTransformMakeRotation(a);
}
I think it could be more optimized (no if), but I can't test myself for the moment. Does it works ?
Your constant 135 is probably incorrect, as atan2 and CGAffineTransformMakeRotation both work in radians, not degrees. The radian equivalent of 135 degrees is π·3/4.
However, other than that, your code looks fine — this should just cause a constant offset, not the odd behavior you describe. Are you sure that cannon.frame.origin is not itself affected by the transformation?