Sprite Kit, Delay on button press - sprite-kit

I am writing a sprite kit game which uses buttons, They are a very important bit of the game. The problem is I need them to have delays, So say you can only press it every 5 minutes. Thanks in advance for your help.
.H file
typedef NS_ENUM(NSInteger, ButtonState)
{
On,
Off
};
#interface Button2 : SKLabelNode
- (instancetype)initWithState:(ButtonState) setUpState;
- (void) buttonPressed;
#end
.M file
#implementation Button2
{
ButtonState _currentState;
}
- (id)initWithState:(ButtonState) setUpState
{
if (self = [super init]) {
_currentState = setUpState;
self = [Button2 labelNodeWithFontNamed:#"Chalkduster"];
self.text = [self updateLabelForCurrentState];
self.fontSize = 30;
}
return self;
}
- (NSString *) updateLabelForCurrentState
{
NSString *label;
if (_currentState == On) {
label = #"Sell";
}
else if (_currentState == Off) {
}
return label;
}
- (void) buttonPressed
{
if (_currentState == Off) {
_currentState = On;
}
else {
_currentState = Off;
}
self.text = [self updateLabelForCurrentState];
}
#end

I am guessing that the touch delegates are being implemented in the scene using which you find the node at the touchPoint and call the buttonPressed method on it.
You can set up a bool flag which can be set when the button is pressed.
In your .h file:
#property BOOL interactionAllowed;
You can access this property in the touch delegate of the scene like:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:touchPoint];
if ([node isKindOfClass:[Button2 class]])
{
Button2 *button = (Button2*)node;
if (button.interactionAllowed)
{
[button buttonPressed];
}
}
}
As for setting (and resetting) the interactionAllowed property:
- (void) buttonPressed
{
if (_currentState == Off) {
_currentState = On;
self.interactionAllowed = NO;
[self runAction:[SKAction sequence:#[[SKAction waitForDuration:3000], [SKAction runBlock:^{
self.interactionAllowed = YES;
}]]]];
}
else {
_currentState = Off;
}
self.text = [self updateLabelForCurrentState];
}

Related

Making one slate in XCode

I am beginning developing with XCode, and I am starting doing some exercises and practises. I am trying to do an easy one, one drawing example in iPhone, an slate with one touch event, but I am doing something wrong; I am a little bit lost.
I create my HDPizarra class and I am triying to keep the moves. I have got one Erase button, with one IBAction that must clean the slate and restart the view; I put the lines in red colour and of 2 of width and I put the touch LocationInView of star and end. But it doesn’t go; it starts the view but when I touch the sreen nothing happens. This is the code:
-(IBAction)borrar: (id)sender
{
[lineas removeAllObjects];
}
- (id)initWithFrame: (CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
-(NSMutableArray *)lineas{
if (_lineas == nil) {
_lineas = [NSMutableArray new];
}
return _lineas;
}
- (void)drawRect: (CGRect)rect
{
if (!lineas) {
lineas = [[NSMutableArray alloc] initWithCapacity:0];
}
CGContextRef contexto = UIGraphicsGetCurrentContext();
UIColor * rojo = [UIColor redColor];
CGContextSetStrokeColorWithColor(contexto, rojo.CGColor);
CGContextSetLineWidth(contexto, 2);
CGContextMoveToPoint(contexto, inicio.x, inicio.y);
CGContextAddLineToPoint(contexto, fin.x, fin.y);
CGContextStrokePath(contexto);
}
-(void)touchesBegan: (NSSet *)touches withEvent: (UIEvent *)event{
UITouch * touch = [touches anyObject];
inicio = [touch locationInView:self];
fin = [touch locationInView:self];
[self setNeedsDisplay];
}
-(void)touchesMoved: (NSSet *)touches withEvent: (UIEvent *)event{
UITouch * touch = [touches anyObject];
fin = [touch locationInView:self];
HDLinea * linea = [[HDLinea alloc] initWithRect:CGRectMake(inicio.x, inicio.y, fin.x, fin.y)];
[self.lineas addObject: linea];
inicio.x = fin.x;
inicio.y = fin.y;
[self setNeedsDisplay];
}
The moves are from an HDLinea object, in one NSMutableArray; the code of .h is:
#import <Foundation/Foundation.h>
#interface HDLinea : NSObject
#property (readwrite) CGRect puntos;
-(id) initWithRect: (CGRect) puntos;
#end
And the one of the implementation is:
#import "HDLinea.h"
#implementation HDLinea
#synthesize puntos = _puntos;
- (id)initWithRect: (CGRect)puntos
{
self = [super init];
if (self) {
self.puntos = puntos;
}
return self;
}
#end
Any idea? Thanks a lot!!

How to add a magnifier to custom control?

How to add a magnifier to custom control? Control is a child of UIView. (It's a UIWebView - but native magnification functionality doesn't work at some pages.)
UPDATED:
Maybe it's possible to force a draw of magnifier on UIWebView?
1. Add the following files to your project:
MagnifierView.h:
//
// MagnifierView.h
// SimplerMaskTest
//
#import <UIKit/UIKit.h>
#interface MagnifierView : UIView {
UIView *viewToMagnify;
CGPoint touchPoint;
}
#property (nonatomic, retain) UIView *viewToMagnify;
#property (assign) CGPoint touchPoint;
#end
MagnifierView.m:
//
// MagnifierView.m
// SimplerMaskTest
//
#import "MagnifierView.h"
#import <QuartzCore/QuartzCore.h>
#implementation MagnifierView
#synthesize viewToMagnify;
#dynamic touchPoint;
- (id)initWithFrame:(CGRect)frame {
return [self initWithFrame:frame radius:118];
}
- (id)initWithFrame:(CGRect)frame radius:(int)r {
int radius = r;
if ((self = [super initWithFrame:CGRectMake(0, 0, radius, radius)])) {
//Make the layer circular.
self.layer.cornerRadius = radius / 2;
self.layer.masksToBounds = YES;
}
return self;
}
- (void)setTouchPoint:(CGPoint)pt {
touchPoint = pt;
// whenever touchPoint is set, update the position of the magnifier (to just above what's being magnified)
self.center = CGPointMake(pt.x, pt.y-66);
}
- (CGPoint)getTouchPoint {
return touchPoint;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect bounds = self.bounds;
CGImageRef mask = [UIImage imageNamed: #"loupe-mask#2x.png"].CGImage;
UIImage *glass = [UIImage imageNamed: #"loupe-hi#2x.png"];
CGContextSaveGState(context);
CGContextClipToMask(context, bounds, mask);
CGContextFillRect(context, bounds);
CGContextScaleCTM(context, 1.2, 1.2);
//draw your subject view here
CGContextTranslateCTM(context,1*(self.frame.size.width*0.5),1*(self.frame.size.height*0.5));
//CGContextScaleCTM(context, 1.5, 1.5);
CGContextTranslateCTM(context,-1*(touchPoint.x),-1*(touchPoint.y));
[self.viewToMagnify.layer renderInContext:context];
CGContextRestoreGState(context);
[glass drawInRect: bounds];
}
- (void)dealloc {
[viewToMagnify release];
[super dealloc];
}
#end
TouchReader.h:
//
// TouchReader.h
// SimplerMaskTest
//
#import <UIKit/UIKit.h>
#import "MagnifierView.h"
#interface TouchReader : UIView {
NSTimer *touchTimer;
MagnifierView *loop;
}
#property (nonatomic, retain) NSTimer *touchTimer;
- (void)addLoop;
- (void)handleAction:(id)timerObj;
#end
TouchReader.m:
//
// TouchReader.m
// SimplerMaskTest
//
#import "TouchReader.h"
#import "MagnifierView.h"
#implementation TouchReader
#synthesize touchTimer;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.touchTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(addLoop) userInfo:nil repeats:NO];
// just create one loop and re-use it.
if (loop == nil) {
loop = [[MagnifierView alloc] init];
loop.viewToMagnify = self;
}
UITouch *touch = [touches anyObject];
loop.touchPoint = [touch locationInView:self];
[loop setNeedsDisplay];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self handleAction:touches];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self.touchTimer invalidate];
self.touchTimer = nil;
[loop removeFromSuperview];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self.touchTimer invalidate];
self.touchTimer = nil;
[loop removeFromSuperview];
}
- (void)addLoop {
// add the loop to the superview. if we add it to the view it magnifies, it'll magnify itself!
[self.superview addSubview:loop];
// here, we could do some nice animation instead of just adding the subview...
}
- (void)handleAction:(id)timerObj {
NSSet *touches = timerObj;
UITouch *touch = [touches anyObject];
loop.touchPoint = [touch locationInView:self];
[loop setNeedsDisplay];
}
- (void)dealloc {
[loop release];
loop = nil;
[super dealloc];
}
#end
Based on: http://coffeeshopped.com/2010/03/a-simpler-magnifying-glass-loupe-view-for-the-iphone
2. Add the following images:
Used images on the code:
loupe-hi#2x.png:
loupe-mask#2x.png:
Original but centered images with a shadow (not used at this moment):
loupe-shadow-hi#2x.png:
loupe-shadow-mask#2x.png:
3. Replace the main UIView on your xib-file by TouchReader
The magnifier will work automaticaly except controls that captures touch events themselfs (for example, UIWebView). And the code above doesn't support the images with a shadow. Please add new answer to the qustion if you successfully fix this issue.
UPDATED:
Change the following code to add UIWebView support. UIView should remain UIView.
#interface TouchReader : UILongPressGestureRecognizer
And add a gesture to webView:
TouchReader* gestureMagnifier = [[[TouchReader alloc] initWithTarget:self action:#selector(handleMagnifier:)] autorelease];
gestureMagnifier.webView = editSource;
gestureMagnifier.delegate = self;
gestureMagnifier.minimumPressDuration = 0.5;
[webView addGestureRecognizer:gestureMagnifier];
TouchReader.h:
//- (void)handleAction:(id)timerObj;
-(void) handleGestureAction:(CGPoint)location;
TouchReader.m:
-(void)awakeFromNib
{
UILongPressGestureRecognizer * longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[self addGestureRecognizer:longPressGesture];
}
-(void)handleGesture:(UILongPressGestureRecognizer *)longPressGesture
{
CGPoint location = [longPressGesture locationInView:self];
switch (longPressGesture.state) {
case UIGestureRecognizerStateBegan:
self.touchTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(addLoop)
userInfo:nil
repeats:NO];
// just create one loop and re-use it.
if(loop == nil){
loop = [[MagnifierView alloc] init];
loop.viewToMagnify = self;
}
loop.touchPoint = location;
[loop setNeedsDisplay];
break;
case UIGestureRecognizerStateChanged:
[self handleGestureAction:location];
break;
case UIGestureRecognizerStateEnded:
[self.touchTimer invalidate];
self.touchTimer = nil;
[loop removeFromSuperview];
loop=nil;
break;
default:
break;
}
}
- (void)addLoop {
// add the loop to the superview. if we add it to the view it magnifies, it'll magnify itself!
[self.superview addSubview:loop];
}
-(void) handleGestureAction:(CGPoint)location
{
loop.touchPoint = location;
[loop setNeedsDisplay];
}
You don't need the touches... methods any more.

How to recognize oneTap/doubleTap at moment?

I Know filtering oneTap/doubleTap using a Apple API. code are follows.
UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleDoubleTap:)];
doubleTapGestureRecognizer.numberOfTapsRequired = 2;
[self addGestureRecognizer:doubleTapGestureRecognizer];
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleTapGestureRecognizer.numberOfTapsRequired = 1;
**[singleTapGestureRecognizer requireGestureRecognizerToFail: doubleTapGestureRecognizer];**
[self addGestureRecognizer:singleTapGestureRecognizer];
but oneTap/doubleTap checkDelayTime is feeling a so Long (About 0.5sec?).
Generally App Users of the reaction is very fast. Although 0.5 seconds is typically short-time. but In Mobile Device Environment is long-time, because users react is very important.
Speaking to the point, YouTubeApp have a very Perfectly algorithm about filtering at a moment oneTap/doubleTap. oneTap-doubleTap checkDelay is VeryVeryShort Perfectly Optimization.
oneTap(show/hidden controlBar)
doubleTap(full/default videoScreenSize)
How to implement like YoutubeApp? about oneTap-doubleTap filtering Not Using a requireGestureRecognizerToFail Selector. about very short delay oneTap-doubleTap distinguishing.
I think YoutubeApp is Not Use a requireGestureRecognizer Selector.
The easiest way to do this is to subclass UITapGestureRecognizer and not a general UIGestureRecognizer.
Like this:
#import <UIKit/UIGestureRecognizerSubclass.h>
#define UISHORT_TAP_MAX_DELAY 0.2
#interface UIShortTapGestureRecognizer : UITapGestureRecognizer
#end
And simply implement:
#implementation UIShortTapGestureRecognizer
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(UISHORT_TAP_MAX_DELAY * NSEC_PER_SEC)), dispatch_get_main_queue(), ^
{
// Enough time has passed and the gesture was not recognized -> It has failed.
if (self.state != UIGestureRecognizerStateRecognized)
{
self.state = UIGestureRecognizerStateFailed;
}
});
}
#end
This is easiest to do without gesture recognizers. Then you can control the delay. The code below is a variation of Apple's original documentation that I use in one of my projects. I have blog post that talks about it as well.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if (touch.tapCount == 2) {
//This will cancel the singleTap action
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if (touch.tapCount == 1) {
//if they tapped within the coin then place the single tap action to fire after a delay of 0.3
if (CGRectContainsPoint(coin.frame,[touch locationInView:self.view])){
//this is the single tap action being set on a delay
[self performSelector:#selector(onFlip) withObject:nil afterDelay:0.3];
}else{
//I change the background image here
}
} else if (touch.tapCount == 2) {
//this is the double tap action
[theCoin changeCoin:coin];
}
}
only thing you need to do is add extra line of code to use requireGestureRecognizerToFail
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
then whole code become to:
UITapGestureRecognizer *doubleTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(beginComicTransitions:)] autorelease];
doubleTapRecognizer.numberOfTapsRequired = 2;
doubleTapRecognizer.numberOfTouchesRequired = 1;
doubleTapRecognizer.delegate = self;
UITapGestureRecognizer *singleTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(bringMenu:)] autorelease];
singleTapRecognizer.numberOfTapsRequired = 1;
singleTapRecognizer.numberOfTouchesRequired = 1;
singleTapRecognizer.delegate = self;
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
here's requireGestureRecognizerToFail means:
if not recognized double tap, then single tap be recognized
if recognized double tap, will not recognize single tap
swift version code is:
let doubleTap = UITapGestureRecognizer(target: self, action: "doubleTapped:")
doubleTap.numberOfTapsRequired = 2
doubleTap.numberOfTouchesRequired = 1
self.scrollView.addGestureRecognizer(doubleTap)
let singleTap = UITapGestureRecognizer(target: self, action: "singleTap:")
singleTap.numberOfTapsRequired = 1
singleTap.numberOfTouchesRequired = 1
self.scrollView.addGestureRecognizer(singleTap)
singleTap.requireGestureRecognizerToFail(doubleTap)
Here is a simple custom gesture recognizers for double taps where you can specify the maximum allowed time between taps. This is based on #Walters answer.
PbDoubleTapGestureRecognizer.h :
#interface PbDoubleTapGestureRecognizer : UIGestureRecognizer
#property (nonatomic) NSTimeInterval maximumDoubleTapDuration;
#end
PbDoubleTapGestureRecognizer.m :
#import "PbDoubleTapGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
#interface PbDoubleTapGestureRecognizer ()
#property (nonatomic) int tapCount;
#property (nonatomic) NSTimeInterval startTimestamp;
#end
#implementation PbDoubleTapGestureRecognizer
- (id)initWithTarget:(id)target action:(SEL)action {
self = [super initWithTarget:target action:action];
if (self) {
_maximumDoubleTapDuration = 0.3f; // assign default value
}
return self;
}
-(void)dealloc {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
- (void)reset {
[super reset];
[NSObject cancelPreviousPerformRequestsWithTarget:self];
self.tapCount = 0;
self.startTimestamp = 0.f;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
if (touches.count != 1 ) {
self.state = UIGestureRecognizerStateFailed;
} else {
if (self.tapCount == 0) {
self.startTimestamp = event.timestamp;
[self performSelector:#selector(timeoutMethod) withObject:self afterDelay:self.maximumDoubleTapDuration];
}
self.tapCount++;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
if (self.tapCount > 2) {
self.state = UIGestureRecognizerStateFailed;
} else if (self.tapCount == 2 && event.timestamp < self.startTimestamp + self.maximumDoubleTapDuration) {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
NSLog(#"Recognized in %f", event.timestamp - self.startTimestamp);
self.state = UIGestureRecognizerStateRecognized;
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
self.state = UIGestureRecognizerStateFailed;
}
- (void)timeoutMethod {
self.state = UIGestureRecognizerStateFailed;
}
#end
You can use it like this:
PbDoubleTapGestureRecognizer *doubleTapGr = [[PbDoubleTapGestureRecognizer alloc]initWithTarget:self action:#selector(_doubleTapAction)];
doubleTapGr.maximumDoubleTapDuration = 0.4;
[yourView addGestureRecognizer:doubleTapGr];
You can combine this with requireGestureRecognizerToFail: to get the behavior that was asked for.
Swift 3.1 version of eladleb's answer.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
if self?.state != .recognized {
self?.state = .failed
}
}
}
Here's a simpler answer to this problem, if you already have an action attached to the button or view. First, change the IBAction so that it includes the UIEvent (don't forget to reconnect it to your button or view in the Storyboard):
-(IBAction)buttonAction:(id)sender forEvent:(UIEvent*)event
Next, in your you can capture the touches from the event, and then easily test for the tap count:
-(IBAction)buttonAction:(id)sender forEvent:(UIEvent*)event {
UITouch* firstTouch = nil;
if ((nil != ((firstTouch = event.allTouches.allObjects.firstObject)))
&& (2 == firstTouch.tapCount))
{
// do something for double-tap
} else {
// do something for single-tap
}
}
You can extend this solution with other cases for different event parameters, such as long taps.
#interface NaMeClass ()
#property (nonatomic, strong) UITapGestureRecognizer * singleTap;
#property (nonatomic, strong) NSTimer *timer;
#end
//...code...
//viewDidLoad
self.singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapIcon:)];
self.singleTap.numberOfTapsRequired = 1;
self.singleTap.cancelsTouchesInView = YES;
self.singleTap.delaysTouchesBegan = YES;
[self addGestureRecognizer:self.singleTap];
//.....code
-(void)tapIcon:(UITapGestureRecognizer *)tapGesture
{
if (tapGesture.state == UIGestureRecognizerStateEnded){
if (!self.timer) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.2
target:self selector:#selector(singleTap) userInfo:nil repeats:NO];
}else{
[self doubleTap];
}
}
}
-(void)singleTap{
[self.timer invalidate];
self.timer = nil;
NSLog(#"1111111111111");
}
-(void)doubleTap{
[self.timer invalidate];
self.timer = nil;
NSLog(#"22222222222");
}

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

Change Sprite with Buttons - Cocos2d

I have 2 buttons (left and right) and a sprite sheet that contains all 55 images. I was wondering, what is the best way to go through each sprite using the buttons?
E.G.
Press the left button and the first sprite is added. Press the right button, the first sprite is removed and the second sprite to added. So on and so forth until it reaches the last image.
This is the Sprite Sheet
#import "cocos2d.h"
#interface GameScene : CCLayer {
CCSpriteBatchNode *pspriteSheet
}
+(CCScene *) scene;
#property (nonatomic, retain) CCSprite *p;
#end
----------------------------------------------------
#import "GameScene.h"
#implementation GameScene
#synthesize p = _p;
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
GameScene *layer = [GameScene node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if ((self = [super init]))
{
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
#"PAnim.plist"];
pspriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"PAnim.pvr.ccz"];
[self addChild:pspriteSheet z:0];
}
return self;
}
- (void) dealloc
{
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
_p = nil;
[CCSpriteFrameCache purgeSharedSpriteFrameCache];
[CCTextureCache purgeSharedTextureCache];
[super dealloc];
}
Should I just keep adding them and removing them?
E.G.
-(void)buttons:(CGPoint)touchLocation
{
if (CGRectContainsPoint(leftB.boundingBox, touchLocation) && tapP == YES && paused == NO) {
if (count == 1)
{
_p = [CCSprite spriteWithSpriteFrameName:#"p1.png"];
[pspriteSheet addChild:_p];
count = 2;
_p.position = ccp(240, 215);
}
if (CGRectContainsPoint(rightB.boundingBox, touchLocation) && tapP == YES && paused == NO) {
if (count == 2)
{
[pspriteSheet removeChild:_p cleanup:YES];
_p = [CCSprite spriteWithSpriteFrameName:#"p2.png"];
_p.position = ccp(240, 215);
[pspriteSheet addChild:_p];
count = 3;
}
}
Here is where the "buttons" method is called
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
[self buttons:touchLocation];
return TRUE;
}
Since it is using spriteframe, you can use setDisplay frame:
CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:#"spr1.png"];
[mySprite setDisplayFrame:frame];
This would save up memory instead of always adding and removing..