how to scroll CCLayer smoothly? - cocos2d-iphone

I want to scroll my map by touching. Could you give me basic concepts how to reach it? Here is my ugly simple code. Just modifying layer's position by each touch moving. It works, but it's not cute as could be.
.h
CGPoint *touchBegin;
CGPoint *touchmove;
.m
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector]
convertToGL:touchLocation];
touchBegin=new CGPoint(touchLocation);
}
-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation =
[[CCDirector sharedDirector] convertToGL:touchLocation];
touchmove = new CGPoint(touchLocation);
[self setPosition:ccp(self.position.x/100-(touchBegin->x-touchmove->x),self.position.y/100.0f)];
delete touchmove;
touchmove=NULL;
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
if (touchBegin)
{
delete touchBegin;
touchBegin=NULL;
}
if (touchmove)
{
delete touchmove;
touchmove=NULL;
}
}

Try CCScrollLayer Extension. Here is link
« First add both files to your project
« In your scene import CCScrollLayer.h
« In your scene's init method construct each layer and pass it to the CCScrollLayer class
For more details refer CCScrollLayerTestLayer.m in cocos2d-iphone-extensions

Related

Having trouble deselecting my CCSprite on drag event, selectedSprite = nil not working

I'm using code that has previously worked in other project the only difference is that this time I'm using a custom sprite class which seems to be not deselecting itself
Ive made a video here of the problem
https://www.youtube.com/watch?v=VHaTpiVPP_w&feature=youtu.be
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouch = [event allTouches];
UITouch *touch = [[allTouch allObjects]objectAtIndex:0];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector]convertToGL:location];
DragItems = [[NSMutableArray alloc]initWithObjects:
Bubble01,
Bubble02,
Bubble03,
Bubble04,
Bubble05,
Bubble06,
nil];
for(int i = 0; i < [DragItems count]; i++)
{
sprite = (Bubble *)[DragItems objectAtIndex:i];
//if(sprite.tag ==12 && CGRectContainsPoint([sprite boundingBox],location))
if(CGRectContainsPoint([sprite boundingBox], location))
{
selectedSprite = sprite;
}
}
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//Move touched sprite
NSSet *allTouch = [event allTouches];
UITouch *touch = [[allTouch allObjects]objectAtIndex:0];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector]convertToGL:location];
selectedSprite.position = ccp(location.x, location.y);
NSLog(#"Position: %f %f",location.x, location.y);
}
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouch = [event allTouches];
UITouch *touch = [[allTouch allObjects]objectAtIndex:0];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector]convertToGL:location];
selectedSprite = nil;
}
drag on CCLayer sometimes working
With the very kind help of rahul_send89 we solved the problem,
firstly the custom class a cclayer was changed to accept its own touches, then in the init
[self setContentSize:[BackBubble boundingBox].size]; was used to size the layer
(so other touches fire, this is what was probably messing up the touches for me)
the link above contains all the code. thanks again for the help!

Kobold2d: KKInput anyTouchEndedThisFrame

The anyTouchEndedThisFrame must be buggy I´ve tried about everything now, and it will only reckonize a touch that´s ended if I move the finger, if I touch and let go at the same spot it does not reckonize it, If I am wrong please correct me
-(void) moveObjectToNewPosition:(KKInput *)input
{
if (input.anyTouchEndedThisFrame) {
[self touchesEnded:[input locationOfAnyTouchInPhase:KKTouchPhaseAny]];
} if (input.anyTouchBeganThisFrame) {
[self touchesBegan:[input locationOfAnyTouchInPhase:KKTouchPhaseBegan]];
}
it has never worked even to me, you should implement this method which is very simple to use
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
UITouch * touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
}
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
}
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}
and add into your init this:
[self setTouchEnabled:YES];

Cocos2d CCTouchBegan

I'm trying to create a program where when the user touches the screen, a sprite will appear. However, if the user keeps their finger on that Sprite, the sprite will grow bigger until the user lets it go.
Now, I created this program in Cocos2d 1.x and it worked fine. However, when I attempted it in 2.x, the sprite gets created but it doesn't help the Sprite Grow.
The code is the following:
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
redBall = [CCSprite spriteWithFile:#"Circle.png"];
redBall.position = ccp(touchLocation.x, touchLocation.y);
redBallRect = CGRectMake(redBall.anchorPoint.x, redBall.anchorPoint.y, redBall.contentSize.width, redBall.contentSize.height);
[self addChild:redBall];
if (CGRectContainsPoint(redBallRect, touchLocation )) {
NSLog(#"Hello");
growForever = [CCRepeatForever actionWithAction: [CCScaleBy actionWithDuration: .5 scale: 1.2]];
[growForever setTag:1];
[redBall runAction:growForever];
}
return YES;
}
What might be the problem and how do I solve it?
Make sure you enabled touch:
-(void)onEnter
{
[super onEnter];
self.touchEnabled = YES;
}
Use boundingBox to get rect.
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint touchLocation = [myTouch locationInView:[myTouch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
if(CGRectContainsPoint([redBall boundingBox], touchLocation))
{
NSLog(#"Hello");
growForever = [CCRepeatForever actionWithAction: [CCScaleBy actionWithDuration: .5 scale: 1.2]];
[growForever setTag:1];
[redBall runAction:growForever];
}
}

Code Refactoring issue

I have game ready and now I am trying to refactor code. I have derived Spider class from CCNode and used targeted delegate method CCTargetedTouchDelegate.
#interface Spider : CCNode<CCTargetedTouchDelegate> {
CCSprite* spiderSprite;
NSString * spiderKilled;
int killed;
AppDelegate *del;
}
+(id) spiderWithParentNode:(CCNode*)parentNode;
-(id) initWithParentNode:(CCNode*)parentNode;
#end
On Touch spider should be killed and here goes the code:
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint tch = [touch locationInView: [touch view]];
CGPoint touchLocation = [[CCDirector sharedDirector] convertToGL:tch];
// Check if this touch is on the Spider's sprite.
BOOL isTouchHandled = CGRectContainsPoint([spiderSprite boundingBox], touchLocation);
if (isTouchHandled)
{
j = j + 1;
killed ++;
[del setKilledScore:j];
[self removeChild:spiderSprite cleanup:YES];
}
return isTouchHandled;
}
I am adding 10 spiders in GameScene layer using: -
for(int i=0; i <10 ;i++){
[Spider spiderWithParentNode:self];
}
But, unfortunately I am not able to remove spiders and giving me EXC_BAD_ACCESS error on this line: [self removeChild:spiderSprite cleanup:YES];
Please help me overcome this error.
Thanks
Update --
Spider Init code
// Static autorelease initializer, mimics cocos2d's memory allocation scheme.
+(id) spiderWithParentNode:(CCNode*)parentNode
{
return [[[self alloc] initWithParentNode:parentNode] autorelease];
}
-(id) initWithParentNode:(CCNode*)parentNode
{
if ((self = [super init]))
{
[parentNode addChild:self];
del = [[UIApplication sharedApplication] delegate];
CGSize screenSize = [[CCDirector sharedDirector] winSize];
spiderSprite = [CCSprite spriteWithFile:#"spider.png"];
spiderSprite.position = CGPointMake(CCRANDOM_0_1() * screenSize.width, CCRANDOM_0_1() * screenSize.height);
[self addChild:spiderSprite];
// Manually add this class as receiver of targeted touch events.
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:-1 swallowsTouches:YES];
}
return self;
}
If you manually add the class to the CCTouchDispatcher list, you should remove it from there after you're done using it.

Rotating sprite with finger in Cocos2d

I need help figuring out the rotation of a sprite with my finger. The sprite is rotating fine but on the initial touch of my finger it somehow rotates by a few degrees by itself.
Also the rotations only work when the finger is rotated around the center of the sprite.
I am trying to simulate the bicycle wheel and have a gear sprite and a pedal sprite as a child of the gear sprite. I want the bicycle wheel to rotate as I touch the pedal and rotate it. I haven't got that far yet. Right now I am trying to figure out how to get rid of the initial shift the gear makes.
Here is the complete code
#import "BicycleScene.h"
#implementation BicycleScene
+(id) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
BicycleScene *layer = [BicycleScene node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(id) init
{
if ((self=[super init])) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
//place the bicycle sprite
bicycleSprite = [CCSprite spriteWithFile:#"bike_gear.png"];
bicycleSprite.position = ccp(bicycleSprite.contentSize.width/2 + 100, winSize.height/2);
[self addChild:bicycleSprite z:1];
//place the pedal sprite
pedalSprite = [CCSprite spriteWithFile:#"bike_pedal.png"];
[bicycleSprite addChild:pedalSprite z:1];
pedalSprite.position = ccp(150, 15);
//enable touch
self.isTouchEnabled = YES;
[self schedule:#selector(gameLoop:) interval:.1/100];
}
return self;
}
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"Touch begun");
}
-(void)gameLoop:(ccTime) dt{
bicycleSprite.rotation = cocosAngle;
}
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"Touch moved");
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
CGPoint previousLocation = [touch previousLocationInView:[touch view]];
CGPoint touchingPoint = [[CCDirector sharedDirector] convertToGL:location];
CGPoint previousTouchingPoint = [[CCDirector sharedDirector] convertToGL:previousLocation];
CGPoint vector = ccpSub(touchingPoint, bicycleSprite.position);
CGFloat rotateAngle = -ccpToAngle(vector);
previousAngle = cocosAngle;
cocosAngle = CC_RADIANS_TO_DEGREES( rotateAngle);
//bicycleSprite.rotation = cocosAngle;
}
#end
I am slightly confused if the line:
CGPoint vector = ccpSub(touchingPoint, bicycleSprite.position);
should actually be:
CGPoint vector = ccpSub(touchingPoint, previousTouchingPoint );
I tried that as well but it didn't work.
I have also uploaded my complete xcodeproj to 4shared for anyone who wants to take a look here: http://www.4shared.com/file/5BaeW4oe/Healthy.html
#interface MainScene : CCLayer {
CCSprite *dial;
CGFloat dialRotation;
}
+ (id)scene;
#end
---------------------------------
#implementation MainScene
+ (id)scene
{
CCScene *scene = [CCScene node];
CCLayer *layer = [MainScene node];
[scene addChild:layer];
return scene;
}
- (id)init
{
if((self = [super init])) {
CCLOG(#"MainScene init");
CGSize size = [[CCDirector sharedDirector]winSize];
dial = [CCSprite spriteWithFile:#"dial.png"];
dial.position = ccp(size.width/2,dial.contentSize.height/2);
[self addChild:dial];
self.isTouchEnabled = YES;
[self scheduleUpdate];
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)update:(ccTime)delta
{
dial.rotation = dialRotation;
}
- (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, dial.position);
CGFloat firstRotateAngle = -ccpToAngle(firstVector);
CGFloat previousTouch = CC_RADIANS_TO_DEGREES(firstRotateAngle);
CGPoint vector = ccpSub(touchingPoint, dial.position);
CGFloat rotateAngle = -ccpToAngle(vector);
CGFloat currentTouch = CC_RADIANS_TO_DEGREES(rotateAngle);
//keep adding the difference of the two angles to the dial rotation
dialRotation += currentTouch - previousTouch;
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
EDIT: I am sorry I can't get this to stay in code mode. But this is the solution and it should be easy to implement in your code. cheers!
In ccTouchesBegan, use the same code as what you've got in ccTouchesMoved to determine the angle, then move to that angle using CCRotateTo. You will need some handling of the user moving his finger while CCRotateTo is active, perhaps stopping the current action and kicking off another one to move to the new angle.