Limit Sprite Rotation - Cocos2d - iphone

I have two hands on either side of the screen that do not move at all and two thumbs that rotate 360 degrees. I want to limit the thumbs rotation, meaning I only need them to be able to rotate like normal thumbs. I am new to cocos2d so any help will be greatly appreciated. Here is what I have so far
#import "cocos2d.h"
#interface GameScene : CCLayer {
CGFloat lthumbRotation, rthumbRotation;
CCSprite *lthumb, *rthumb;
}
+(CCScene *) scene;
#end
------------------------------------
#import "GameScene.h"
#implementation GameScene
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
GameScene *layer = [GameScene node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if ((self = [super init]))
{
lthumb = [CCSprite spriteWithFile:#"lthumb.png" rect:CGRectMake(0,0, 145, 59)];
lthumb.position = ccp(100, 140);
lthumb.anchorPoint = ccp(0.3, 0.8);
[self addChild:lthumb z:0];
rthumb = [CCSprite spriteWithFile:#"rthumb.png" rect:CGRectMake(0,0, 145, 59)];
rthumb.position = ccp(380, 140);
rthumb.anchorPoint = ccp(0.7, 0.8);
[self addChild:rthumb z:0];
[self scheduleUpdate];
}
return self;
}
-(void)update:(ccTime)delta
{
lthumb.rotation = lthumbRotation;
rthumb.rotation = rthumbRotation;
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
//acquire the previous touch location
CGPoint firstLocation = [touch previousLocationInView:[touch view]];
CGPoint location = [touch locationInView:[touch view]];
//preform all the same basic rig on both the current touch and previous touch
CGPoint touchingPoint = [[CCDirector sharedDirector] convertToGL:location];
CGPoint firstTouchingPoint = [[CCDirector sharedDirector] convertToGL:firstLocation];
CGPoint firstVector = ccpSub(firstTouchingPoint, rthumb.position);
CGFloat firstRotateAngle = -ccpToAngle(firstVector);
CGFloat previousTouch = CC_RADIANS_TO_DEGREES(firstRotateAngle);
CGPoint vector = ccpSub(touchingPoint, rthumb.position);
CGFloat rotateAngle = -ccpToAngle(vector);
CGFloat currentTouch = CC_RADIANS_TO_DEGREES(rotateAngle);
//keep adding the difference of the two angles to the dial rotation
lthumbRotation += currentTouch - previousTouch;
rthumbRotation -= currentTouch - previousTouch;
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void) dealloc
{
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
[super dealloc];
}
#end
This lets both of the thumbs move at the same time in upward/downward angles with the anchor point at the bottom of the thumbs(acting like a joint).
I also need the thumbs rotation to reset back to 0 once the touches have ended.
Thanks in advance

In your ccTouchesMoved:withEvent: method, simply check to see if the new rotation is within a given threshold before applying it to your sprites.
Finally, in ccTouchesEnded:withEvent:, you can simply set the rotation values back to 0:
lthumbRotation = 0;
rthumbRotation = 0;

Related

How I can define the edges?

I have made a code for scrolling a background in Cocos2d to create an effect of a camera, but I cant prevent the camera going beyond the edges of my background. My background is an image that is 1440*1080. My code is:
+(id) scene
{
CCScene* scene = [CCScene node];
TileDemo* layer = [TileDemo node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if ((self = [super init]))
{
self.isTouchEnabled = YES;
CCSprite *Nivel1 = [CCSprite spriteWithFile:#"Nivel1.png"];
Nivel1.position = ccp(0.5f, 0.5f);
[self addChild:Nivel1 z:0 tag:1];
}
return self;
}
-(void) dealloc
{
[super dealloc];
}
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent*)event
{
return YES;
}
-(void) ccTouchEnded:(UITouch*)touch withEvent:(UIEvent*)event
{
}
-(void) ccTouchCancelled:(UITouch*)touch withEvent:(UIEvent*)event
{
}
-(void) ccTouchMoved:(UITouch*)touch withEvent:(UIEvent*)event
{
CGPoint touchLocation = [touch locationInView: [touch view]];
CGPoint prevLocation = [touch previousLocationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
prevLocation = [[CCDirector sharedDirector] convertToGL: prevLocation];
CGPoint diff = ccpSub(touchLocation,prevLocation);
CCNode* node = [self getChildByTag:1];
CGPoint currentPos = [node position];
[node setPosition: ccpAdd(currentPos, diff)];
}
#end
you have to calculate maximum and minimum posiible position of your sprite and check it in your touchMoved:withEvent: method. On my mind, it is easier to calculate these values, when anchorPoint of your sprite is in (0.f, 0.f), instead of standard (0.5f, 0.5f). then your positions will be
CGPoint maxPos = ccp(0.f, 0.f);
CGPoint minPos = ccp((spriteWidth - screenWidth) * (-1), (spriteHeight - screnHeight) * (-1));
then just check if your sprite's new position is in valid range before set it.

Particle engine problem

i am implementing particle engine and here is my code:
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init] ))
{
self.isTouchEnabled = YES;
emitter = [[CCParticleMeteor alloc] init];
emitter.texture = [[CCTextureCache sharedTextureCache] addImage:#"stars.png"];
emitter.position = ccp( 240, 160 );
[self addChild:emitter];
}
return self;
}
-(BOOL) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self ccTouchesMoved:touches withEvent:event];
return YES;
}
-(BOOL) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
CGPoint point = [[CCDirector sharedDirector] convertToGL:location];
emitter.position = ccp(point.x , point.y);
return YES;
}
And Here is the Screen shot:
Here is i want to need:
1-I want to change the direction of effect( Means flame move upward but i want downward).
2-I want to change the color of flame.
Please help if you can.....
1) A quick look at the particle system documentation gives you either angle or gravity to play with - try setting these to different values i.e.
emitter.angle = <the angle you want>
2) Edit stars.png to be the colour you want?

Determine if Sprite Rotated 360 Degrees - Cocos2d

I have a sprite that rotates with touch. I need to be able to determine if it has rotated 360 degrees 3 times. Is there any way to tell?
Here is what I have so far
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "GameScene.h"
#interface G : CCLayer {
CCSprite *g;
CGFloat gRotation;
}
#end
------------------------------------------
#import "G.h"
#implementation G
-(id) init
{
if ((self = [super init]))
{
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
g = [CCSprite spriteWithFile:#"g.png"];
[self addChild:g z:-1];
}
return self;
}
- (void)update:(ccTime)delta
{
g.rotation = gRotation;
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint firstLocation = [touch previousLocationInView:[touch view]];
CGPoint location = [touch locationInView:[touch view]];
CGPoint touchingPoint = [[CCDirector sharedDirector] convertToGL:location];
CGPoint firstTouchingPoint = [[CCDirector sharedDirector] convertToGL:firstLocation];
CGPoint firstVector = ccpSub(firstTouchingPoint, g.position);
CGFloat firstRotateAngle = -ccpToAngle(firstVector);
CGFloat previousTouch = CC_RADIANS_TO_DEGREES(firstRotateAngle);
CGPoint vector = ccpSub(touchingPoint, g.position);
CGFloat rotateAngle = -ccpToAngle(vector);
CGFloat currentTouch = CC_RADIANS_TO_DEGREES(rotateAngle);
gRotation += currentTouch - previousTouch;
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void) dealloc
{
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
[super dealloc];
}
#end
GameScene
#import "GameScene.h"
#import "MainMenu.h"
#import "G.h"
#implementation GameScene
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
GameScene *layer = [GameScene node];
[scene addChild: layer];
return scene;
}
-(void) tapG: (id) sender
{
G *gView;
gView = [[G alloc] init];
gView.position = ccp(100, 100);
[self.parent addChild:gView z:1001];
[gView scheduleUpdate];
[gView release];
}
-(id) init
{
if ((self = [super init]))
{
tG = [CCMenuItemImage itemFromNormalImage:#"tp.png" selectedImage:#"tp.png" disabledImage:#"tpaperd.png" target:self selector:#selector(tapG:)];
gt = [CCMenu menuWithItems:tG, nil];
gt.position = ccp(210, 80);
[gt alignItemsHorizontallyWithPadding:10];
[self addChild:gt z:0];
}
return self;
}
- (void) dealloc
{
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
[super dealloc];
}
Can anyone help? Thanks in advance
cocos2d can take rotations more than 360. but if your going left and right then its a bit more complicated than just checking if sprite.rotation == 1080. if the rotation is happening on your touchesMoved method then what you should do is that you should record your highest rotation (rotation in right maybe) and lowest rotation (the other way) and then the difference should be bigger than 360*3. so add 2 class vars to your G layer float maxRot,minRot;
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
maxRot = mySprite.rotation; // here you set the ivars to defaults.
minRot = mySprite.rotation; // im setting them to your sprite initial rotation
} // incase it is not 0
at the end of your touchesMoved method you check for your conditions:
if (mySprite.rotation > maxRot)
maxRot = mySprite.rotation;
else if (mysprite.rotation < minRot)
minRot = mySprite.rotation;
if ((maxRot - minRot) >= (360*3)) {
// your condition is satisfied
}
i havent tested this so it could be just wrong.. but its worth a shot
EDIT:
the code above will not work unless the rotations are happening in the same direction.. it wont work for your right, left, right condition. I guess one way is to track the direction of your rotation in touchesMoved. so again youll need class vars
int numOfRots;
float previousRot, currentRot, accumRot;
BOOL isPositive, isPreviousPositive;
your touches methods:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
previousRot = mySprite.rotation;
currentRot = mySprite.rotation;
accumRot = 0;
numOfRots = 0;
isPositive = NO;
isPreviousPositive = NO;
}
at the end of touchesMoved you will have the following:
currentRot = mySprite.rotation;
if (currentRot > previousRot)
isPositive = YES;
else
isPositive = NO;
if (isPositive != isPreviousPositive) {
// now we have a change in direction, reset the vars
accumRot = 0;
}
if (isPositive) {
accumRot += abs(currentRot - previousRot);
}
else {
accumRot += abs(previousRot - currentRot);
}
if (accumRot >= 360) {
//now we have one rotation in any direction.
numOfRots++;
//need to reset accumRot to check for another rot
accumRot = 0;
if (numOfRots == 3) {
//BINGO!!! now you have 3 full rotations
}
}
previousRot = currentRot;
isPreviousPositive = isPositive;
hope this helps

Schedule Update from Another Layer

I have an sprite the I need to rotate it with touch but it is located in a different layer. Is it possible to update it's position?
E.G.
Sprite has it's own layer but it's position needs to be updated within the main gamescene
here is what I have so far.
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "GameScene.h"
#interface G : CCLayer {
CCSprite *g;
CGFloat gRotation;
}
#end
------------------------------------------
#import "G.h"
#implementation G
-(id) init
{
if ((self = [super init]))
{
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
g = [CCSprite spriteWithFile:#"g.png"];
[self addChild:g z:-1];
//[self scheduleUpdate];
if (g.rotation == 360)
{
[self unscheduleUpdate];
}
}
return self;
}
- (void)update:(ccTime)delta
{
g.rotation = gRotation;
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint firstLocation = [touch previousLocationInView:[touch view]];
CGPoint location = [touch locationInView:[touch view]];
CGPoint touchingPoint = [[CCDirector sharedDirector] convertToGL:location];
CGPoint firstTouchingPoint = [[CCDirector sharedDirector] convertToGL:firstLocation];
CGPoint firstVector = ccpSub(firstTouchingPoint, g.position);
CGFloat firstRotateAngle = -ccpToAngle(firstVector);
CGFloat previousTouch = CC_RADIANS_TO_DEGREES(firstRotateAngle);
CGPoint vector = ccpSub(touchingPoint, g.position);
CGFloat rotateAngle = -ccpToAngle(vector);
CGFloat currentTouch = CC_RADIANS_TO_DEGREES(rotateAngle);
gRotation += currentTouch - previousTouch;
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void) dealloc
{
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
[super dealloc];
}
#end
GameScene
#import "GameScene.h"
#import "MainMenu.h"
#import "G.h"
#implementation GameScene
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
GameScene *layer = [GameScene node];
[scene addChild: layer];
return scene;
}
-(void) tapG: (id) sender
{
G *gView;
gView = [[G alloc] init];
gView.position = ccp(100, 100);
[self.parent addChild:gView z:1001];
[gView schedule:#selector(update:)];
[gView release];
}
-(id) init
{
if ((self = [super init]))
{
tG = [CCMenuItemImage itemFromNormalImage:#"tp.png" selectedImage:#"tp.png" disabledImage:#"tpaperd.png" target:self selector:#selector(tapG:)];
gt = [CCMenu menuWithItems:tG, nil];
gt.position = ccp(210, 80);
[gt alignItemsHorizontallyWithPadding:10];
[self addChild:gt z:0];
}
return self;
}
- (void) dealloc
{
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
[super dealloc];
}
It brings up the sprite but the sprite does not rotate.
you can schedule updates for another layer.
are you sure your G layer is set to be touch enabled? try gView.isTouchEnabled = YES; after allocating gView. you may need to confirm to the protocol. Add <CCStandardTouchDelegate> to your CCLayer interface: #interface G : CCLayer <CCStandardTouchDelegate> { ....
also you can schedule -(void)update:(ccTime)delta method using [gView scheduleUpdate]; it will give the same result but its more convenient.

iPhone - Wheel tracking finger jumps to same starting position?

I am trying to implement a selection wheel in an iphone application. I have got the wheel to track the users finger but now for some reason when the user touches the screen the wheel jumps so the same section of the wheel tracks the finger each time.
How would I get it so the wheel rotates like the user is dragging it from any point?
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
int tInput = [allTouches count]-1;
UITouch *touch =[[allTouches allObjects] objectAtIndex:tInput];
CGPoint location = [touch locationInView:self.view];
float theAngle = atan2( location.y-imageX.center.y, location.x-imageX.center.x );
CGAffineTransform cgaRotate = CGAffineTransformMakeRotation(theAngle);
imageX.transform = cgaRotate;
}
Any suggestion?
Right - that makes perfect sense - this is indeed what your code does.
What you need to add is the initial value where you started your drag as a relative rotation -- or track your last rotation.
A very elaborate way is shown below - but this should help get the point across.
#interface UntitledViewController : UIViewController {
CGPoint firstLoc;
UILabel * fred;
double angle;
}
#property (assign) CGPoint firstLoc;
#property (retain) UILabel * fred;
#implementation UntitledViewController
#synthesize fred,firstLoc;
- (void)viewDidLoad {
[super viewDidLoad];
self.fred = [[UILabel alloc] initWithFrame:CGRectMake(100,100,100,100)];
fred.text = #"Fred!"; fred.textAlignment = UITextAlignmentCenter;
[self.view addSubview:fred];
angle = 0; // we aint have rotated just yet...
};
// make sure we get them drag events.
- (BOOL)isFirstResponder { return YES; }
-(void)handleObject:(NSSet *)touches
withEvent:(UIEvent *)event
isLast:(BOOL)lst
{
UITouch *touch =[[[event allTouches] allObjects] lastObject];
CGPoint curLoc = [touch locationInView:self.view];
float fromAngle = atan2( firstLoc.y-fred.center.y,
firstLoc.x-fred.center.x );
float toAngle = atan2( curLoc.y-fred.center.y,
curLoc.x-fred.center.x );
// So the angle to rotate to is relative to our current angle and the
// angle through which our finger moved (to-from)
float newAngle = angle + (toAngle - fromAngle);
CGAffineTransform cgaRotate = CGAffineTransformMakeRotation(newAngle);
fred.transform = cgaRotate;
// we only 'save' the current angle when we're done with the drag.
//
if (lst)
angle = newAngle;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch =[[[event allTouches] allObjects] lastObject];
// capture where we started - so we can later work out the
// rotation relative to this point.
//
firstLoc = [touch locationInView:self.view];
};
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self handleObject:touches withEvent:event isLast:NO];
};
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self handleObject:touches withEvent:event isLast:YES];
}
Obviously you can do this a lot more elegant - and above misses a bit of 0 .. 2xPI capping you need.
Because the view itself is still the old one. You may want to fetch the zip example file in:
http://bynomial.com/blog/?p=77
and in PuttyView.m change the:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
....
else {
self.center = CGPointMake(self.center.x + touchPoint.x - touchStart.x,
self.center.y + touchPoint.y - touchStart.y);
into
else {
NSSet *allTouches = [event allTouches];
int tInput = [allTouches count]-1;
UITouch *touch =[[allTouches allObjects] objectAtIndex:tInput];
CGPoint location = [touch locationInView:self];
float theAngle = atan2( location.y-self.center.y, location.x-self.center.x );
CGAffineTransform cgaRotate = CGAffineTransformMakeRotation(theAngle);
self.transform = cgaRotate;
}
where you thus stay within the view and its relative angle. Alternatively - in your code - keep the relative angle itself.