I have add the Gestures Classes available from the example to support the Gesture rcognition.
I have 4 Sprites in the Top Layer to be moved at the Swipe Left/Right and have 3 Sprites to Swipe at the Bottom Layer.
I have the following code
-(id) init
{
// Some Stuff
[Gestures sharedGestures].swipeTolerance = 40;
[Gestures sharedGestures].pointResetLimit = 10;
[Gestures sharedGestures].delegate = self;
[Gestures sharedGestures].useX = NO;
[Gestures sharedGestures].useCircle = NO;
[Gestures sharedGestures].useSquare = NO;
for (int i=1; i<6; i++)
{
NSString *str=[NSString stringWithFormat:#"Howtoplay_0%d.png",i];
topLayer[i]=[CCSprite spriteWithFile:str];
[topLayer[i] setPosition:ccp(640/2,480/2)];
[self addChild:topLayer[i] z:1];
[topLayer[i] setVisible:NO];
}
[topLayer[1] setVisible:YES];
[topLayer[1] setPosition:ccp(320/2,480/2)];
for (int i=1; i<4; i++)
{
NSString *str=[NSString stringWithFormat:#"HowtoplayB_0%d.png",i];
backLayer[i]=[CCSprite spriteWithFile:str];
[backLayer[i] setPosition:ccp((320*i)/2,480/2)];
[self addChild:backLayer[i] z:-1];
}
[backLayer[1] setPosition:ccp(320/2,480/2)];
}
-(void) registerWithTouchDispatcher{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:1 swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
[[Gestures sharedGestures] reset];
return TRUE;
}
-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint point = [touch locationInView: [touch view]];
CGPoint converted = [[CCDirector sharedDirector] convertToGL:point];
[[Gestures sharedGestures] addPoint:converted];
}
-(void) swipeLeftComplete
{
NSLog(#"Swipe Left Complete Called");
[self MoveLeft];
}
-(void) swipeRightComplete
{
[self MoveRight];
}
-(void)MoveLeft
{
[topLayer[currentTop+1] setPosition:ccp(640/2,480/2)];
[topLayer[currentTop+1] setVisible:YES];
[topLayer[currentTop] runAction:[CCMoveTo actionWithDuration:2 position:ccp(-320/2,480/2)]];
[topLayer[currentTop+1] runAction:[CCMoveTo actionWithDuration:2 position:ccp(320/2,480/2)]];
[topLayer[currentTop-1] setVisible:NO];
currentTop+=1;
}
-(void) MoveRight
{
[topLayer[currentTop-1] setVisible:YES];
[topLayer[currentTop] setVisible:YES];
[topLayer[currentTop] runAction:[CCMoveTo actionWithDuration:2 position:ccp(-320/2,480/2)]];
[topLayer[currentTop-1] runAction:[CCMoveTo actionWithDuration:2 position:ccp(320/2,480/2)]];
currentTop--;
}
I am unable to Swipe Right/Left Smoothly it gives the overlapping of the topLayer. Please Help me to smoothen the layer movement.
Any kind of Help will be Appreciated
Thanks...
Your issue sounds similar to problems I, and others, have faced with tiling sprites and borders between them. Try adding this to the top of your init statement:
[[CCDirector sharedDirector] setProjection:CCDirectorProjection2D];
Related
I've been stuck on this problem for days. What I have is multiple SKSpriteNode's, one for a left arrow, right arrow and up arrow. When I hold down the right arrow I want my character to continue moving right while its being held down, on the other hand if you press the up Arrow then you will only jump once regardless of if you hold it down.
So my problem for example is when i hold the right arrow and then i press the up arrow, touchesEnded is called and it stops my character from moving right even though I still have my finger on the right arrow
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
for (UITouch *touch in touches){
CGPoint location = [touch locationInNode:self];
if (CGRectContainsPoint(rightArrow.frame, location)){
[wizard setTexture:[SKTexture textureWithImageNamed:#"wizardRight"]];
didTouchRightArrow = YES;
isLookingRight = YES;
isLookingLeft = NO;
rightArrow.alpha = 0.5;
NSLog(#"Touching right");
}
if (CGRectContainsPoint(leftArrow.frame, location)){
[wizard setTexture:[SKTexture textureWithImageNamed:#"wizardLeft"]];
isLookingRight = NO;
isLookingLeft = YES;
didTouchLeftArrow = YES;
leftArrow.alpha = 0.5;
NSLog(#"Touching left");
}
if (CGRectContainsPoint(upArrow.frame, location)){
didTouchUpArrow = YES;
upArrow.alpha = 0.5;
NSLog(#"Touching up");
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
if (rightArrow.alpha != 1.0){
rightArrow.alpha = 1.0;
}
if (leftArrow.alpha != 1.0){
leftArrow.alpha = 1.0;
}
if (upArrow.alpha != 1.0){
upArrow.alpha = 1.0;
for (UITouch *touch in touches){
CGPoint location = [touch locationInNode:self];
if (CGRectContainsPoint(rightArrow.frame, location)){
NSLog(#"Touching right");
didTouchRightArrow = YES;
} {
NSLog(#"Not touching right");
didTouchRightArrow = NO;
}
if (CGRectContainsPoint(leftArrow.frame, location)){
NSLog(#"Touching Left");
didTouchLeftArrow = YES;
} else {
NSLog(#"not touching left");
didTouchLeftArrow = NO;
}
didTouchUpArrow = NO;
}
This may not be the right way to approach the problem, but in touchesEnded I am trying to see if the touch is still in the desired Rect.
You need a way to identify the different nodes which are registering a touch. There is more than one way to do this but I have always found using the name property of a node to be the simplest and easiest to work with.
You already have the right idea by using the BOOLs to register the touch states.
I wrote some code to handle what you are trying to accomplish:
#import "GameScene.h"
#implementation GameScene {
SKSpriteNode *node0;
SKSpriteNode *node1;
BOOL node0touch;
BOOL node1touch;
}
-(void)didMoveToView:(SKView *)view {
self.backgroundColor = [SKColor blackColor];
node0 = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(100, 100)];
node0.name = #"node0";
node0.position = CGPointMake(100, 300);
[self addChild:node0];
node1 = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(100, 100)];
node1.name = #"node1";
node1.position = CGPointMake(400, 300);
[self addChild:node1];
node0touch = false;
node1touch = false;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:touchLocation];
if([node.name isEqualToString:#"node0"])
node0touch = true;
if([node.name isEqualToString:#"node1"])
node1touch = true;
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:touchLocation];
if([node.name isEqualToString:#"node0"])
node0touch = false;
if([node.name isEqualToString:#"node1"])
node1touch = false;
}
}
-(void)update:(CFTimeInterval)currentTime {
if(node0touch)
NSLog(#"node0 touch");
if(node1touch)
NSLog(#"node1 touch");
}
I am using MHRotaryKnob to make Rotary dial like animation. I am using it for making old telephone dial pad.. At present it is just showing animation when i dial the pad it just come back with animation. even the first circle from lower not even getting touch detected and touch is working there also where there is no circle to dial. Below i am posting the code i am using.
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint point = [touch locationInView:self];
if (self.interactionStyle == MHRotaryKnobInteractionStyleRotating)
{
// If the touch is too close to the center, we can't calculate a decent
// angle and the knob becomes too jumpy.
if ([self squaredDistanceToCenter:point] < MinDistanceSquared)
return NO;
// Calculate starting angle between touch and center of control.
_angle = [self angleBetweenCenterAndPoint:point];
}
else
{
_touchOrigin = point;
_angle = [self angleForValue:self.value];
}
self.highlighted = YES;
[self showHighlighedKnobImage];
_canReset = NO;
return YES;
}
- (BOOL)handleTouch:(UITouch *)touch
{
if (touch.tapCount > 1 && self.resetsToDefault && _canReset)
{
[self setValue:self.defaultValue animated:YES];
return NO;
}
CGPoint point = [touch locationInView:self];
if (self.interactionStyle == MHRotaryKnobInteractionStyleRotating)
{
if ([self squaredDistanceToCenter:point] < MinDistanceSquared)
return NO;
// Calculate how much the angle has changed since the last event.
float newAngle = [self angleBetweenCenterAndPoint:point];
float delta = newAngle - _angle;
_angle = newAngle;
// We don't want the knob to jump from minimum to maximum or vice versa
// so disallow huge changes.
if (fabsf(delta) > 45.0f)
return NO;
self.value += (self.maximumValue - self.minimumValue) * delta / (MaxAngle*2.0f);
// Note that the above is equivalent to:
//self.value += [self valueForAngle:newAngle] - [self valueForAngle:angle];
}
else
{
self.value = [self valueForPosition:point];
}
return YES;
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
if ([self handleTouch:touch] && self.continuous)
[self sendActionsForControlEvents:UIControlEventValueChanged];
return YES;
}
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
self.highlighted = NO;
[self showNormalKnobImage];
// You can only reset the knob's position if you immediately stop dragging
// the knob after double-tapping it, i.e. when tracking ends.
_canReset = YES;
[self handleTouch:touch];
[self sendActionsForControlEvents:UIControlEventValueChanged];
[self setValue:self.defaultValue animated:YES];
}
I am trying to achieve that which circle is selected to dial that can be detected and only circles can be used to dial not outside the circles. Thanks in advance, any sort of help is appreciated.
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.
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
I was following Ray`s tutorial for making a simple iPhone game (here: http://goo.gl/fwPi) , and decided that i wanted the enemies to be eliminated when they get touched.
My initial approach was to spawn a small CCSprite sprite on the touch location, then use CGRectMake to create a bounding box of said sprite to detect if the enemy sprite was touched. Much like Ray does with the projectile/enemy. But of course, my way of doing it isnt working and i cant dig myself out of this hole.
Here is the relevant code snippet. Any help is appreciated:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// Choose one of the touches to work with
UITouch *touch = [touches anyObject];
CGPoint location = [self convertTouchToNodeSpace: touch];
location = [[CCDirector sharedDirector] convertToGL:location];
CCSprite *touchedarea = [CCSprite spriteWithFile:#"Icon-72.png" rect:CGRectMake(location.x, location.y, 2, 2)];
touchedarea.tag = 2;
[self addChild:touchedarea];
[_touchedareas addObject:touchedarea];
}
- (void)update:(ccTime)dt {
NSMutableArray *touchedareasToDelete = [[NSMutableArray alloc] init];
for (CCSprite *touchedarea in _touchedareas) {
CGRect touchedareaRect = CGRectMake(
touchedarea.position.x,
touchedarea.position.y,
touchedarea.contentSize.width,
touchedarea.contentSize.height);
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
for (CCSprite *target in _targets) {
CGRect targetRect = CGRectMake(
target.position.x - (target.contentSize.width/2),
target.position.y - (target.contentSize.height/2),
target.contentSize.width,
target.contentSize.height);
if (CGRectIntersectsRect(touchedareaRect, targetRect)) {
[targetsToDelete addObject:target];
}
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
}
if (targetsToDelete.count > 0) {
[touchedareasToDelete addObject:touchedarea];
}
[targetsToDelete release];
}
for (CCSprite *touchedarea in touchedareasToDelete) {
[_touchedareas removeObject:touchedarea];
[self removeChild:touchedarea cleanup:YES];
}
[touchedareasToDelete release];
}
That looks like a very difficult way to go about doing it. I havent been coding long myself but maybe the following might help you.
lets say u have a nsmutablearray called enemies and you add the new enemy object to this array when ever you create one. enemy object would be a ccnode and have a ccsprite within it called _enemySprite
then do the touch
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
UITouch * touch = [[allTouches allObjects] objectAtIndex:0];
//UITouch* touch = [touches anyObject];
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
int arraysize = [enemies count];
for (int i = 0; i < arraysize; i++) {
if (CGRectContainsPoint( [[[enemies objectAtIndex:i] _enemySprite] boundingBox], location)) {
//some code to destroy ur enemy here
}
}
// NSLog(#"TOUCH DOWN");
}
hope this helps
Another way of doing it is that calculating distance between touch position and your sprites.. If touch is close enough to one of your sprites, you can kill it.. Something like this..
for (CCSprite *sprite in anArrayThatCOntainsAllYourSprites) {
float distance = pow(sprite.position.x - location.x, 2) + pow(sprite.position.y - location.y, 2);
distance = sqrt(distance);
if (distance <= 10) {
sprite.dead = YES;
}
}