How to shoot arrow in Box2d? - iphone

I am trying to shoot arrow with force in left to right direction on Touches Ended method.I applied linear impulse to B2Body, but it is not shooting in correct direction.
Here is my code
(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"ended");
//Add a new body/atlas sprite at the touched location
CGPoint location;
for( UITouch *touch in touches )
{
location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
}
if (fabs(ccpDistance(startTouchPosition, location)) < 3) {
return;
}
CGPoint diff = ccpSub(startTouchPosition, location);
diff = CGPointMake(-diff.x, -diff.y);
//CGFloat distanceX = bird.position.x - 50.0;
// CGFloat distanceY = bird.position.y - 160.0;
CGFloat velocityX = diff.x*-1/5;
CGFloat velocityY = diff.y*-1/5;
b2Vec2 birdVelocity = b2Vec2(velocityX,velocityY);
//make b2Body
CGFloat sphereX = arrow.position.x/PTM_RATIO;
CGFloat sphereY = arrow.position.y/PTM_RATIO;
b2BodyDef bodyDef;
bodyDef.position.Set(sphereX,sphereY);
bodyDef.type = b2_dynamicBody;
int num = 6;
b2Vec2 verts[] = {
b2Vec2(-56.5f / PTM_RATIO, 0.8f / PTM_RATIO),
b2Vec2(-51.9f / PTM_RATIO, -2.6f / PTM_RATIO),
b2Vec2(53.7f / PTM_RATIO, -2.2f / PTM_RATIO),
b2Vec2(58.7f / PTM_RATIO, 0.7f / PTM_RATIO),
b2Vec2(52.5f / PTM_RATIO, 3.0f / PTM_RATIO),
b2Vec2(-55.0f / PTM_RATIO, 1.2f / PTM_RATIO)
};
b2PolygonShape polyShape;
polyShape.Set(verts, num);
b2FixtureDef fixtureDef;
fixtureDef.shape= &polyShape;
fixtureDef.density=4;
fixtureDef.restitution=0.1;
fixtureDef.friction=0.5;
b2Body * physicsBird = world->CreateBody(&bodyDef);
physicsBird->CreateFixture(&fixtureDef);
physicsBird->GetUserData();
arrow.rotation=atan2f(arrow.position.x-startTouchPosition.x,arrow.position.y-startTouchPosition.y)*180/M_PI +90;
direction = arrow.rotation;
b2Vec2 force = b2Vec2(direction, 24.8);
physicsBird->ApplyLinearImpulse(force, physicsBird->GetWorldCenter());
physicsBird->SetLinearDamping(0.4);
}
but it is not working.Please help!

Related

How to rotate and point to cursor location in SpriteKit?

I am working with the SpriteKit's Spaceship Demo and I want it to rotate to the location of where I click on the screen and then move toward it.
The current code I have only makes it move up the screen starting at position 50,50:
sprite.position = CGPointMake(50,50);
SKAction *fly = [SKAction moveByX:0.0F y:50.0F duration:1];
[sprite runAction:[SKAction repeatActionForever:fly];
How would I make it work?
So long answer, this will help you.(I benefited from raywenderlich's book)
//Math Utilities
static inline CGPoint CGPointSubtract(const CGPoint a,
const CGPoint b)
{
return CGPointMake(a.x - b.x, a.y - b.y);
}
static inline CGPoint CGPointMultiplyScalar(const CGPoint a,
const CGFloat b)
{
return CGPointMake(a.x * b, a.y * b);
}
static inline CGFloat CGPointLength(const CGPoint a)
{
return sqrtf(a.x * a.x + a.y * a.y);
}
static inline CGPoint CGPointNormalize(const CGPoint a)
{
CGFloat length = CGPointLength(a);
return CGPointMake(a.x / length, a.y / length);
}
static inline CGPoint CGPointAdd(const CGPoint a,
const CGPoint b)
{
return CGPointMake(a.x + b.x, a.y + b.y);
}
static const float SHIP_SPEED = 60.0;
#implementation yourScene
{
SKSpriteNode *ship;
NSTimeInterval _lastUpdateTime;
NSTimeInterval _dt;
CGPoint _velocity;
CGPoint _lastTouchLocation;
}
-(void)didMoveToView:(SKView *)view
{
ship = [SKSpriteNode spriteNodeWithImageNamed:#"Spaceship"];
ship.position = CGPointMake(50, 50);
[self addChild:ship];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
[self moveShipToward:touchLocation];//Move Toward
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
{
if (_lastUpdateTime) {
_dt = currentTime - _lastUpdateTime;
} else {
_dt = 0;
}
_lastUpdateTime = currentTime;
CGPoint offset = CGPointSubtract(_lastTouchLocation, ship.position);
float distance = CGPointLength(offset);
if (distance < SHIP_SPEED * _dt) {
ship.position = _lastTouchLocation;
_velocity = CGPointZero;
} else {
[self moveSprite:ship velocity:_velocity];
[self rotateSprite:ship toFace:_velocity];
}
}
}
- (void)moveShipToward:(CGPoint)location
{
_lastTouchLocation = location;
CGPoint offset = CGPointSubtract(location, ship.position);
CGPoint direction = CGPointNormalize(offset);
_velocity = CGPointMultiplyScalar(direction, SHIP_SPEED);
}
- (void)moveSprite:(SKSpriteNode *)sprite
velocity:(CGPoint)velocity
{
CGPoint amountToMove = CGPointMultiplyScalar(velocity, _dt);
sprite.position = CGPointAdd(sprite.position, amountToMove);
}
- (void)rotateSprite:(SKSpriteNode *)sprite
toFace:(CGPoint)direction
{
sprite.zRotation = atan2f(direction.y, direction.x);
}

Can't get the bullet image to spawn at right location

hi guys I have this Sprite Kit cannon game that it works perfectly but with one problem. if I point the cannon to a very top or very bottom as you can see in the image, the bullet since it is spawning from the center of the cannon's sprite, it shows clearly that the bullet is being fired not from the cannon's tunnel but from the center of the image, how can I fix this bullet position so that it would always spawn from the mouth of the tunnel.
here is my code so far.
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint location = [_Player position];
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
bullet = [SKSpriteNode spriteNodeWithImageNamed:#"cannonbullet"];
bullet.xScale = 0.06;
bullet.yScale = 0.06;
bullet.position =
CGPointMake(location.x+_Player.zRotation,location.y+_Player.zRotation);
bullet.zPosition = 0;
CGPoint offset = rwSub(touchLocation, bullet.position);
if (offset.x <= 0) return;
[self addChild:bullet];
CGPoint direction = rwNormalize(offset);
CGPoint shootAmount = rwMult(direction, 400);
CGPoint realDest = rwAdd(shootAmount, bullet.position);
float velocity = 480.0/1.0;
float realMoveDuration = self.size.width / velocity;
SKAction * actionMove = [SKAction moveTo:realDest duration:realMoveDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
[bullet runAction:[SKAction sequence:#[actionMove, actionMoveDone]]];
[self animStarter];
}
as you can see in the image the bullet is spawning from a very off location if the cannon is not shooting straight.
Make sure that your cannon's barrel sprite image is lined up with the center X axis of the image (see the picture). You can drag out or copy the image if you want to duplicate the project.
Below is the code to rotate the cannon to the touch location and fire a cannonball once it has reached the the desired rotation angle. I think you are still using the zombie conga code so I used its functions for your convenience.
#import "MyScene.h"
static inline CGPoint CGPointSubtract(const CGPoint a,
const CGPoint b)
{
return CGPointMake(a.x - b.x, a.y - b.y);
}
static inline CGPoint CGPointMultiplyScalar(const CGPoint a,const CGFloat b)
{
return CGPointMake(a.x * b, a.y * b);
}
static inline CGFloat CGPointLength(const CGPoint a)
{
return sqrtf(a.x * a.x + a.y * a.y);
}
static inline CGPoint CGPointNormalize(const CGPoint a)
{
CGFloat length = CGPointLength(a);
return CGPointMake(a.x / length, a.y / length);
}
static inline CGFloat CGPointToAngle(const CGPoint a)
{
return atan2f(a.y, a.x);
}
static inline CGFloat ScalarSign(CGFloat a)
{
return a >= 0 ? 1 : -1;
}
static inline CGFloat ScalarShortestAngleBetween(const CGFloat a, const CGFloat b)
{
CGFloat difference = b - a;
CGFloat angle = fmodf(difference, M_PI * 2);
if (angle >= M_PI) {
angle -= M_PI * 2;
}
return angle;
}
static const float ROTATE_RADIANS_PER_SEC = 4 * M_PI;
static const float MOVE_POINTS_PER_SEC = 120.0;
#implementation MyScene
{
SKSpriteNode *cannon;
NSTimeInterval _lastUpdateTime;
NSTimeInterval _dt;
CGPoint _velocity;
CGPoint _lastTouchLocation;
BOOL fireCannon;
CGPoint destination;
}
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
[self createCannon];
fireCannon = false;
}
return self;
}
-(void)createCannon
{
cannon = [SKSpriteNode spriteNodeWithImageNamed:#"cannon"];
cannon.position = CGPointMake(self.size.height/2, self.size.width/2);
[self addChild:cannon];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
fireCannon = true;
destination = touchLocation;
_lastTouchLocation = touchLocation;
CGPoint offset = CGPointSubtract(touchLocation, cannon.position);
CGPoint direction = CGPointNormalize(offset);
_velocity = CGPointMultiplyScalar(direction, MOVE_POINTS_PER_SEC);
}
-(void)update:(CFTimeInterval)currentTime
{
if (_lastUpdateTime) {
_dt = currentTime - _lastUpdateTime;
} else {
_dt = 0;
}
_lastUpdateTime = currentTime;
[self rotateSprite:cannon toFace:_velocity rotateRadiansPerSec:ROTATE_RADIANS_PER_SEC];
}
- (void)rotateSprite:(SKSpriteNode *)sprite
toFace:(CGPoint)velocity
rotateRadiansPerSec:(CGFloat)rotateRadiansPerSec
{
float targetAngle = CGPointToAngle(velocity);
float shortest = ScalarShortestAngleBetween(cannon.zRotation, targetAngle);
float amtToRotate = rotateRadiansPerSec * _dt;
if (ABS(shortest) < amtToRotate)
{
amtToRotate = ABS(shortest);
}
sprite.zRotation += ScalarSign(shortest) * amtToRotate;
if ((ABS(shortest) == amtToRotate) && (fireCannon == true))
{
fireCannon = false;
[self fire:targetAngle];
}
}
-(void)fire:(float)targetAngle
{
SKSpriteNode *cannonBall = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(5, 5)];
cannonBall.position = cannon.position;
[self addChild:cannonBall];
int x = cannon.position.x + 1000 * cos(targetAngle);
int y = cannon.position.y + 1000 * sin(targetAngle);
[cannonBall runAction:[SKAction moveTo:CGPointMake(x, y) duration:2]];
}
#end

Check Rotation in iphone SDk

In my app, i used SMRotatory wheel for rotation. It is working fine as rotation regarding.
But i want to detect that rotation is clockwise or anti-clockwise??
//My code is as follow:
- (BOOL)continueTrackingWithTouch:(UITouch*)touch withEvent:(UIEvent*)event
{
CGFloat radians = atan2f(container.transform.b, container.transform.a);
// NSLog(#"rad is %f", radians);
CGPoint pt = [touch locationInView:self];
float dx = pt.x - container.center.x;
float dy = pt.y - container.center.y;
float ang = atan2(dy,dx);
float angleDifference = deltaAngle - ang;
// NSLog(#"%f",angleDifference);
if (angleDifference>=0) {
//NSLog(#"positive");
[[NSUserDefaults standardUserDefaults]setValue:#"positive" forKey:#"CheckValue"];
}
else
{
// NSLog(#"negative");
[[NSUserDefaults standardUserDefaults]setValue:#"negative" forKey:#"CheckValue"];
}
container.transform = CGAffineTransformRotate(startTransform, -angleDifference);
bg.transform=CGAffineTransformRotate(startTransform, -angleDifference);
return YES;
}
Try something like this:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentTouch1=[touch locationInView:self.superview];
CGPoint currentTouch2=[touch previousLocationInView:self.superview];
CGFloat x = currentTouch2.x - currentTouch1.x;
CGFloat y = currentTouch2.y - currentTouch1.y;
CGFloat dist = sqrtf(x*x + y*y);
CGFloat cx = currentTouch1.x - self.superview.bounds.size.width / 2;
CGFloat cy = currentTouch2.y - self.superview.bounds.size.height / 2;
CGFloat cdist = sqrtf(cx*cx + cy*cy);
CGFloat angle = atan2(dist, cdist);
//NSLog(#"%f",angle);
CGFloat radians = atan2f(super.transform.b, super.transform.a);
mDegrees = radians * (180 / M_PI);
if (mDegrees < 0.0)
{
mDegrees+=360;
}
NSLog(#"Angle is = %f",angle); //positive is clockwise, negative is counterclockwise
CGAffineTransform transform = CGAffineTransformRotate(self.transform, angle);
self.transform = transform;
touch1 = currentTouch1;
touch2 = currentTouch2;
}

box2d concave body

I am creating a box2d body for my iOS game, that is built from 4 shapes that are convex.
The problem is that it fails when calling the init method.
Here's my code:
#implementation Banan
-(void)createBodyAtLocation:(CGPoint)location
{
int num;
float density = 1.0f;
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position = b2Vec2(location.x/PTM_RATIO/RETSIZE, location.y/PTM_RATIO/RETSIZE);
body = world->CreateBody(&bodyDef);
body -> SetUserData(self);
//first shape
b2FixtureDef fixtureDef1;
b2PolygonShape shape1;
num = 4;
b2Vec2 verts1[4];
verts1[0].Set(58.9f / PTM_RATIO, 46.3f / PTM_RATIO);
verts1[1].Set(63.3f / PTM_RATIO, 41.5f / PTM_RATIO);
verts1[2].Set(47.4f / PTM_RATIO, 15.6f / PTM_RATIO);
verts1[3].Set(43.6f / PTM_RATIO, 24.3f / PTM_RATIO);
shape1.Set(verts1, num);
fixtureDef1.shape = &shape1;
fixtureDef1.density = density;
//second
b2FixtureDef fixtureDef2;
b2PolygonShape shape2;
num = 5;
b2Vec2 verts2[5];
verts2[0].Set(42.1f / PTM_RATIO, 21.7f / PTM_RATIO);
verts2[1].Set(46.6f / PTM_RATIO, -0.1f / PTM_RATIO);
verts2[2].Set(29.1f / PTM_RATIO, -32.2f / PTM_RATIO);
verts2[3].Set(2.5f / PTM_RATIO, -45.2f / PTM_RATIO);
verts2[4].Set(6.8f / PTM_RATIO, -10.4f / PTM_RATIO);
shape2.Set(verts2, num);
fixtureDef2.shape = &shape2;
fixtureDef2.density = density;
//third
b2FixtureDef fixtureDef3;
b2PolygonShape shape3;
num = 4;
b2Vec2 verts3[4];
verts3[0].Set(5.6f / PTM_RATIO, -9.7f / PTM_RATIO);
verts3[1].Set(-0.3f / PTM_RATIO, -45.7f / PTM_RATIO);
verts3[2].Set(-32.7f / PTM_RATIO, -41.2f / PTM_RATIO);
verts3[3].Set(-28.2f / PTM_RATIO, -15.7f / PTM_RATIO);
shape3.Set(verts3, num);
fixtureDef3.shape = &shape3;
fixtureDef3.density = density;
//fourth
b2FixtureDef fixtureDef4;
b2PolygonShape shape4;
num = 4;
b2Vec2 verts4[4];
verts4[0].Set(-28.7f / PTM_RATIO, -14.8f / PTM_RATIO);
verts4[1].Set(-40.8f / PTM_RATIO, -36.0f / PTM_RATIO);
verts4[2].Set(-60.5f / PTM_RATIO, -2.4f / PTM_RATIO);
verts4[3].Set(-58.0f / PTM_RATIO, 2.9f / PTM_RATIO);
shape4.Set(verts3, num);
fixtureDef4.shape = &shape4;
fixtureDef4.density = density;
//attach to shape
body->CreateFixture(&fixtureDef1);
body->CreateFixture(&fixtureDef2);
body->CreateFixture(&fixtureDef3);
body->CreateFixture(&fixtureDef4);
}
- (id)initWithWorld:(b2World *)tworld atLocation:(CGPoint)location {
if ((self = [super init])) {
world = tworld;
[self initWithFile:#"Banana.png"];
[self createBodyAtLocation:location];
}
return self;
}
-(void)dealloc
{
[super dealloc];
}
#end
The '-initWithWorld: atLocation:' method is invoked by ccTouchBegan method and then kills my app.
The errors are the following:
Assertion failed: (area > 1.19209290e-7F), function ComputeCentroid, ...
-(void)createBananaAtLocation:(CGPoint)location
{
Banan *ban = [[[Banan alloc] initWithWorld:world atLocation:location] autorelease];//fails at this line when is invoked
[self addChild:ban];
}
-(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector]
convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
b2Vec2 locationWorld =
b2Vec2(touchLocation.x/PTM_RATIO, touchLocation.y/PTM_RATIO);
[self createBananaAtLocation:touchLocation]; //error at this line
return YES;
}
In your case vertices are oriented clockwise, while b2Polygon requirement is counterclockwise.
It leads to calculation of negative area of the polygon. You have to change order of your vertices.

UIView resizing and Rotation issue

Hi friends in my app i want to allow users to resize,rotate and flip an image,
here i have used the below code to resize,
CGFloat angleToRotate ;CGPoint currentTouchPoint,previousTouchPoint; UITouch *touch;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
touch = [[event allTouches] anyObject];
//if (![touch.view isKindOfClass:[vw class]]) {
touchStart = [[touches anyObject] locationInView:self];
kResizeThumbSize=15;
isResizingLR = (self.bounds.size.width - touchStart.x < kResizeThumbSize && self.bounds.size.height - touchStart.y < kResizeThumbSize);
isResizingUL = (touchStart.x <kResizeThumbSize && touchStart.y <kResizeThumbSize);
isResizingUR = (self.bounds.size.width-touchStart.x < kResizeThumbSize && touchStart.y<kResizeThumbSize);
isResizingLL = (touchStart.x <kResizeThumbSize && self.bounds.size.height -touchStart.y <kResizeThumbSize);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
currentTouchPoint = [touch locationInView:self.superview];
previousTouchPoint = [touch previousLocationInView:self.superview];
CGPoint touchPoint1 = [[touches anyObject] locationInView:self.superview];
CGPoint previous1=[[touches anyObject]previousLocationInView:self.superview];
CGPoint touchPoint = [[touches anyObject] locationInView:self];
CGPoint previous=[[touches anyObject]previousLocationInView:self];
float deltaWidth = touchPoint.x-previous.x;
float deltaHeight = touchPoint.y-previous.y;
float deltaWidth1 = currentTouchPoint.x-previousTouchPoint.x;
float deltaHeight1 = currentTouchPoint.y-previousTouchPoint.y;
CGFloat newW= self.superview.frame.size.width+deltaWidth1;
if (isResizingLR) {
self.superview.frame = CGRectMake(self.superview.frame.origin.x, self.superview.frame.origin.y,self.superview.frame.size.width+deltaWidth1,self.superview.frame.size.height+deltaHeight1);
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y,self.frame.size.width+deltaWidth,self.frame.size.height+deltaHeight);
[self setNeedsDisplayInRect:CGRectMake(self.frame.origin.x, self.frame.origin.y,self.frame.size.width+deltaWidth,self.frame.size.height+deltaHeight)];
}
if (isResizingUL) {
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width - deltaWidth, self.frame.size.height - deltaHeight);
self.superview.frame = CGRectMake(self.superview.frame.origin.x + deltaWidth1, self.superview.frame.origin.y + deltaHeight1, self.superview.frame.size.width - deltaWidth1, self.superview.frame.size.height - deltaHeight1);
[self setNeedsDisplayInRect:CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width - deltaWidth, self.frame.size.height - deltaHeight)];
}
if (isResizingUR) {
self.frame = CGRectMake(self.frame.origin.x ,self.frame.origin.y, self.frame.size.width + deltaWidth, self.frame.size.height - deltaHeight);
self.superview.frame = CGRectMake(self.superview.frame.origin.x ,self.superview.frame.origin.y+deltaHeight1, self.superview.frame.size.width + deltaWidth1, self.superview.frame.size.height - deltaHeight1);
[self setNeedsDisplayInRect:CGRectMake(self.frame.origin.x ,self.frame.origin.y, self.frame.size.width + deltaWidth, self.frame.size.height - deltaHeight)];
}
if (isResizingLL) {
self.frame = CGRectMake(self.frame.origin.x ,self.frame.origin.y , self.frame.size.width - deltaWidth, self.frame.size.height + deltaHeight);
self.superview.frame = CGRectMake(self.superview.frame.origin.x + deltaWidth1 ,self.superview.frame.origin.y , self.superview.frame.size.width - deltaWidth1, self.superview.frame.size.height + deltaHeight1);
[self setNeedsDisplayInRect:CGRectMake(self.frame.origin.x ,self.frame.origin.y , self.frame.size.width - deltaWidth, self.frame.size.height + deltaHeight)];
CGSize supersize=self.superview.frame.size;
NSLog(#"superview frame in resize: %#",NSStringFromCGSize(supersize));
}
if (!isResizingUL && !isResizingLR && !isResizingUR && !isResizingLL) {
CGPoint center = CGPointMake(CGRectGetMidX([self.superview bounds]), CGRectGetMidY([self.superview bounds]));
// [self.superview setContentMode:UIViewContentModeRedraw];
CGFloat angleInRadians = atan2f(currentTouchPoint.y - center.y, currentTouchPoint.x - center.x) - atan2f(previousTouchPoint.y - center.y, previousTouchPoint.x - center.x);
CGFloat angleInRadians1 = atan2f(touchPoint.y - center.y, touchPoint.x - center.x) - atan2f(previous.y - center.y, previous.x - center.x);
[self.superview setTransform:CGAffineTransformRotate([self.superview transform], angleInRadians)];
}
}
Here i can able to resize and rotate but, when i resize AFTER ROTATION the resize is doing somehing plz help me.
use this code for change view size
[UIView animateWithDuration:2
delay:1.0
options: UIViewAnimationCurveEaseOut
animations:^{
// set your resize image;
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
yourview.transform = CGAffineTransformMakeRotation(M_PI_2*1.90);//change 1.90 your transform
[UIView commitAnimations];