cocos2d rotating sprite collision detection - iphone

I got 2 sprites, ball and arrow.
the arrow is not moving.
the ball is rotating on it's anchor point.
id rotate = [CCRotateBy actionWithDuration:.5 angle: 360];
I want to detect collision when the ball reaches to arrow.
Tried CGRectIntersectsRect but it does not detect collision.
Any help?
Thanks...

You probably don't want this answer, but I would use Box2D or Chipmunk and use the Vertex Helper application to specify vertices.

use circle-circle collision method.. here is the method..
-(float)asbs:(CGPoint)_arrowPos ballPos:(CGPoint)_ballPos
{
float x = _arrowPos.x-_ballPos.x;
float y = _arrowPos.y-_ballPos.y;
float xy = x*x+y*y;
return xy;
}
if([self asbs:arrow.position ballPos:ball.position]<=size)
{
//collision
}
note that size = ball radius + arrow radius * ball radius + arrow radius
the method above is using a(square) + b(square) = c(square) to check distance between two points..

You might need to convert the ball to world space in an update method then call that rather than the balls position. If it is in a parent layer is position will always be static in respect to its parent.

Related

can't offset ccnode to let me center my main character

I have a standard cocos2d startup layer( HelloWorldLayer). I created another class of type CCNode named "Terrain" for my terrain. Then i add it to my layer in the layer's init:
terrain = [[Terrain alloc] initWithWorld:world AndLevel:0];
[self addChild:terrain z:1];
i add a 'CarObject' class (a CCSprite class), and add a car object to my terrain
car = [[CarObject alloc] initWithWorld:world];
[terrain addChild:car];
-i.e. in both the initWithWorld for terrain and car, i initialize some Box2d code
I then try to center my car object to my screen when i move it, i do this in my update method:
float offsetX = car.position.x;
float offsetY = car.position.y;
[terrain setOffsetX:(int)offsetX andOffsetY:(int)offsetY];
where the setOffsetX.. method is:
- (void) setOffsetX:(int)newOffsetX andOffsetY:(int)newOffsetY {
_offsetX = newOffsetX;
_offsetY = newOffsetY;
CGSize winSize = [CCDirector sharedDirector].winSize;
self.position = CGPointMake(-(_offsetX - winSize.width/2), -(_offsetY - winSize.height/2));
}
When i use a NSLog to see if the terrain position changes, i can see that the position actually chages, but the view does not. What am i doing wrong? am sure it's a dumb mistake!
btw, if i try this in my HelloWorldLayer's update method (instead of [terrain setOffsetX..])
self.position = CGPointMake(self.position.x-1, self.position.y);
the terrain is moving.
Car is a child of Terrain. Car's position is therefore relative to Terrain's position. Since you base Terrain's position on Car's position, which is actually relative to Terrain's position, you may be simply running into the effect that your position updates simply cancel each other out.
If you want to move the Terrain while keeping the Car centered, you shouldn't add the Car as a child of Terrain. Instead add it to the same node as the Terrain (HelloWorldLayer). Then you can move the Car and Terrain independently of each other.

Moving a sprite with touches began, casting and parameters in obj - c?

I've been reading a book on the cocos2d framework for ios5 for a few days and have developed a small game that the book walks you through. To control the sprite in this game you use the accelerometer:
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
float deceleration = 0.4f;
float sensitivity = 6.0f;
float maxVelocity = 100;
// adjust velocity based on current accelerometer acceleration
playerVelocity.x = playerVelocity.x * deceleration + acceleration.x * sensitivity;
// we must limit the maximum velocity of the player sprite, in both directions (positive & negative values)
if (playerVelocity.x > maxVelocity)
{
playerVelocity.x = maxVelocity;
}
else if (playerVelocity.x < -maxVelocity)
{
playerVelocity.x = -maxVelocity;
}
// Alternatively, the above if/else if block can be rewritten using fminf and fmaxf more neatly like so:
// playerVelocity.x = fmaxf(fminf(playerVelocity.x, maxVelocity), -maxVelocity);
}
Now I'm wondering if I can change this code to allow the sprite to still accelerate/decelerate along the x axis, but to use touch input rather than the accelerometer, and to go faster the longer the touch is held down for? So a touch to the right would move the sprite to that spot slowly, if the touch is released, it stops moving to that spot. The longer a touch is held down, the faster the sprite moves.
is there anything in the framework to allow me to implement a rotation mechanism that allows my sprite to rotate to the position that the touch was in, so it looks like its facing the point thats been touched?
Well, afaik theres no method that will determine the angle to the touch and then rotate the sprite accordingly, but if you have the x and y coordinates of the sprite and the touch you can calculate it yourself fairly easily.
CGPoint spriteCenter; // this should represent the center position of the sprite
CGPoint touchPoint; //location of touch
float distanceX = touchPoint.x - spriteCenter.x;
float distanceY = touchPoint.y - spriteCenter.y;
float angle = atan2f(distanceY,distanceX); // returns angle in radians
// do whatever you need to with the angle
Once you have the angle you can set the rotation of the sprite.

Cocos2D Rotation and Anchor point

The problem that I have is that when ever I change the anchor point sprite automatically rotates with respect to the current anchor point. And I don't want that to happen.
The steps that I followed
create a sprite with anchor point (0.5, 0.5)
Changed the anchor point to (0,1)
Rotated the sprite to 90 degree. (Using CCRotateBy. Sprite rotated correctly)
Changed the anchor point to (0.5, 0.5) (Every thing is fine till now. And this is the position that I need to keep). Now sprite.rotation is 90.
I changed the anchor point to (1,0) (Sprite automatically rotates to 90 degree with respect to the given anchor point - I need to stop this behavior)
Is there any way to reset the rotation of sprite to 0, without actually rotating the texture(ie., to keep the texture in its current form - actual texture rotated to 90 degrees) and changing anchor point or position along with step 4, so that I can continue from point 5.
As Lukman says, the anchor point will always affect rotation, since your goal is to be able to specify the sprite position with a different anchor point from the rotation I would suggest making an empty CCNode as a parent of your sprite.
This way, you can set the position on sprite to be relative to this parent node to compensate for your anchor point change and then keep the anchor point for rotation on the sprite but use the parent node for position.
anchorPoint affects both position and rotation. You cannot stop it from affecting either one of them.
But from reading your question, since you want to prevent anchorPoint from affecting the rotation, I'm assuming here that the reason you change the anchorPoint is for the position, for example you are setting it to be ccp(1, 0) because you want to the sprite bottom right corner, instead of the sprite center, to be where you set the position is.
My suggestion is: don't change the anchorPoint at all, but change the way you set the sprite position. You can use this small function to adjust the position:
CGPoint adjustedPosition(const CGPoint position, const CGPoint anchor, const CGSize size) {
return CGPointMake(position.x - (anchor.x - 0.5) * size.width, position.y - (anchor.y - 0.5) * size.height);
}
Now, assuming you wanted to use anchorPoint of (1,0) when doing the positioning, instead of sprite.position = ccp(200, 300), you just need to do:
sprite.position = adjustedPosition(ccp(200, 300), ccp(1.0, 0.0), sprite.contentSize);
If you want, I'll post the logic behind the math later. Otherwise, I hope this will help.
Maybe it will help you to install an anchor for the sprites in the correct coordinate.
void SetAnchorPosition(CCSprite * sprite, const CCPoint & point)
{
static CCSize winSize = CCDirector::sharedDirector()->getWinSize();
double x = ((double)1/(double)winSize.width)*(double)point.x;
double y = ((double)1/(double)winSize.height)*(double)point.y;
sprite->setAnchorPoint(ccp(x,y));
sprite->setPosition(point);
}
You can add a line in the touchEnded method as a forceful alternative:
-(void)touchEnded:(UITouch *)touch withEvent:(UIEvent *)event{
_yourSprite.rotation = 90;
}

Destroying Sprites in and around the Collided Sprite

I need help in destroying the sprites which are in and around the collided sprites ie in a radius of 2.5 cms all sprites should be destroyed. Idea here is i will be shooting a projectile from bottom to the objects falling from the top. Once collision happens all the sprites around that radius also should be destroyed. Like a Bomb Effect. I have used box2d for collision ie contact listener. How to go about doing that?
Please Suggest:-)
Regards,
Karthik
Hold an array of your sprites, or if you are using a batchNode you can do that.
When the collision happens, go through your sprites. Check the distance with their position and the explosion center and kill them if they are in range.
e.g.
CCSprite *sprite;
for (sprite in [batchNode descendants]) {
if ([sprite isInRangeOf:[explosionSprite position]]) {
[sprite yourRemovalMethod];
}
}
the method 'isInRangeOf:' would be within your sprite subclass
Something like..
-(BOOL) isInRangeOf:(CGPoint)explosionCenter {
//Use pythagoras theorem to work out the distance between [sprite position] and [explosionCenter]
CGFloat dx = explosionCenter.x - [self position].x;
CGFloat dy = explosionCenter.y - [self position].y;
float distance = sqrt(dx*dx + dy*dy );
// If your distance is less than or equal to your 'death radius' return YES, else No.
if (distance <= 25) {
return TRUE;
} else {
return FALSE;
}
}
Hope that helps.

How to rotate image around center point automatically with finger touch

On iPhone, how to implement rotating image around the center point using finger touch ?
Just like wheel, if you put finger on the iPhone screen , then move suddenly, then the image becoming rotating around center point just like the wheel, after a while, it becomes more and more slow , finally stop.
Who can help to give some pieces of codes (Object-C) or some suggest ?
I was working with a "spin the bottle"-app yesterday. On the window I have a ImageView with an bottle that's suppose to response to touches and rotate the way the user swipes his finger. I struggled to get my ImageView to rotate during the touch-events (TouchesBegan, Touchesoved, TouchesEnd). I used this code in TouchesMoved to find out the angle in witch to rotate the image.
public override void TouchesMoved (NSSet touches, UIEvent evt)
{
PointF pt = (touches.AnyObject as UITouch).LocationInView(this);
float x = pt.X - this.Center.X;
float y = pt.Y - this.Center.Y;
double ang = Math.Atan2(x,y);
// yada yada, rotate image using this.Transform
}
THIS IS IMPORTANT! When the ImageView rotates, even the x & y-coordinates changes. So touching the same area all the time would give me different values in the pt and prePt-points. After some thinking, googeling and reading I came up with an simple solution to the problem. The "SuperView"-property of the ImageView.
PointF pt = (touches.AnyObject as UITouch).LocationInView(this.SuperView);
Having that small change in place made it alot easier, no i can use the UITouch-metohs LocationInView and PreviousLocationInView and get the right x & y coordinates. Her is parts of my code.
float deltaAngle;
public override void TouchesMoved (NSSet touches, UIEvent evt)
{
PointF pt = (touches.AnyObject as UITouch).LocationInView(this.Superview);
float x = pt.X - this.Center.X;
float y = pt.Y - this.Center.Y;
float ang = float.Parse(Math.Atan2(dx,dy).ToString());
//do the rotation
if (deltaAngle == 0.0) {
deltaAngle = ang;
}
else
{
float angleDif = deltaAngle - ang;
this.Transform = CGAffineTransform.MakeRotation(angleDif);
}
}
Hope that helped someone from spending hours on how to figure out how to freaking rotate a bottle! :)
I would use the affine transformations - yuou can assign a transformation to any layer or UI element using the transform property.
You can create a rotation transform using CGAffineTransform CGAffineTransformMakeRotation( CGFloat angle) which will return a transformation that rotates an element. The default rotation should be around the centerpoint.
Be aware, the rotation is limited to 360 degrees, so if you want to rotate something more than that (say through 720 degrees) - you have to break the rotation into several sequences.
You may find this SO article useful as well.
The transform property of a view or layer can be used to rotate the image displayed within. As far as the spinning part goes, you just track the location and movement of touches in your view with touchesBegan, touchesMoved, and touchesEnded.
Use the distance and time between the touches updates to calculate a speed, and use that to set a rotational velocity. Once you start the image spinning, update the position periodically (with an NSTimer, maybe), and reduce the rotational velocity by some constant.