I'm working on a game and I started getting this after I added a menu on the story board, even after deleting it, I get this error:
2014-09-05 19:55:22.155 hygvhgvbv[2875:60b] Cannot find executable for CFBundle 0x998cb40 </Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.1.sdk/System/Library/AccessibilityBundles/CertUIFramework.axbundle> (not loaded)
hygvhgvbv(2875,0x20581a8) malloc:
*** mach_vm_map(size=8388608) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
libc++abi.dylib: terminating with uncaught exception of type std::bad_alloc: std::bad_alloc
Here's my code:
Myscene.h
#import <SpriteKit/SpriteKit.h>
#interface MyScene : SKScene
#property (strong, nonatomic) SKLabelNode *scoreLabel;
#property (nonatomic) NSInteger score;
#property (nonatomic) BOOL gameOver;
#property SKEmitterNode *shatter;
typedef NS_ENUM(NSInteger, SpriteType) {
SpriteTypeBackground,
SpriteTypeSquare
};
Myscene.m
#import "MyScene.h"
#interface MyScene()
#property SKSpriteNode *background;
#property SKSpriteNode *square;
#end
#implementation MyScene
#define kNumberOfColors 2 //Setting total number of possible colors
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
[self runAction:[SKAction repeatActionForever: [SKAction sequence:#[[SKAction performSelector:#selector(addSquareAndBackground) onTarget:self] ]]]];
//Score Label
float margin = 10;
self.scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
self.scoreLabel.text = #"Score: 0";
self.scoreLabel.fontSize = [self convertFontSize:14];
self.scoreLabel.zPosition = 4;
self.scoreLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft;
self.scoreLabel.position = CGPointMake(margin, margin);
[self addChild:self.scoreLabel];
}
return self;
}
- (float)convertFontSize:(float)fontSize
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
return fontSize * 2;
} else {
return fontSize;
}
}
-(void)addSquareAndBackground {
_background = [self createSpriteWithType:SpriteTypeBackground];
_square = [self createSpriteWithType:SpriteTypeSquare];
}
-(void)removeSquareAndBackground {
[_background removeFromParent];
[_square removeFromParent];
}
-(SKSpriteNode *) createSpriteWithType:(SpriteType)type {
// Select a color randomly
NSString *colorName = [self randomColorName];
SKSpriteNode *sprite;
if (type == SpriteTypeBackground) {
NSString *name = [NSString stringWithFormat:#"%#Outline",colorName];
sprite = [SKSpriteNode spriteNodeWithImageNamed:name];
sprite.name = name;
sprite.size = CGSizeMake(CGRectGetHeight(self.frame), CGRectGetWidth(self.frame));
}
else {
sprite = [SKSpriteNode spriteNodeWithImageNamed:colorName];
sprite.name = [NSString stringWithFormat:#"%#Sprite",colorName];
sprite.size = CGSizeMake(50, 50);
}
sprite.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
[self addChild:sprite];
return sprite;
}
- (NSString *) randomColorName {
NSString *colorName;
switch (arc4random_uniform(kNumberOfColors)) {
case 0:
colorName = #"blue";
break;
case 1:
colorName = #"pink";
break;
// Add more colors here
default:
break;
}
return colorName;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
NSString *pinkShatterPath = [[NSBundle mainBundle] pathForResource:#"pinkShatter" ofType:#"sks"];
SKEmitterNode *pinkShatter = [NSKeyedUnarchiver unarchiveObjectWithFile:pinkShatterPath];
pinkShatter.particlePosition = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
if (node == _square) {
// Extract the color name from the node name
NSArray *squareNameParts = [node.name componentsSeparatedByCharactersInSet:[NSCharacterSet uppercaseLetterCharacterSet]];
// Extract the color name from the node name
NSArray *backgroundNameParts = [_background.name componentsSeparatedByCharactersInSet:[NSCharacterSet uppercaseLetterCharacterSet]];
// Compare if the colors match
if ([backgroundNameParts[0] isEqualToString: squareNameParts[0]]) {
//Add SKAction to add 1 to score label
[SKAction performSelector:#selector(removeSquareAndBackground) onTarget:self];
[self addChild:pinkShatter];
self.score += 10;
//NSLog(#"Score"); for console error detection
} else {
//NSLog(#"Lost"); //Add SKAction to display game-over menu
SKLabelNode *gameOverLabel = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
gameOverLabel.text = #"You Lose!!!!!";
gameOverLabel.fontSize = 20;
gameOverLabel.zPosition = 4;
gameOverLabel.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
[gameOverLabel setScale:0.1];
[self addChild:gameOverLabel];
[gameOverLabel runAction:[SKAction scaleTo:1.0 duration:0.5]];
self.gameOver = YES;
return;
}
}
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
[self.scoreLabel setText:[NSString stringWithFormat:#"Score: %ld", (long)self.score]];
}
#end
I can't figure out how to fix these errors.
Related
Okay, so in my SpriteKit game, I have an SKAction that waits and then calls a method. I have this action repeating forever. The methods spawns sprites. When I press a button (another sprite) the game pauses, and stops the action by removing it. When either resume or restart (also sprites) is pressed the action starts again and the sprites spawn.
However, when returning from the background (after the app is left) and the pause menu method automatically gets called, when I press the resume or restart button, the action does not run for some reason. Here's my code:
In GameScene.m:
-(void)createSceneContents {
self.isPaused = NO;
self.world = [SKNode node];
[self createUI];
[self createPauseMenu];
self.spawningSpeed = 1.5;
self.enemyData = [[Enemy alloc]init];
SKAction *wait = [SKAction waitForDuration:self.spawningSpeed];
SKAction *run = [SKAction performSelector:#selector(spawningEnemy) onTarget:self];
self.spawnAction = [SKAction repeatActionForever:[SKAction sequence:#[wait,run]]];
[self.world runAction:self.spawnAction withKey:#"spawn"];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(wentToForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
[self addChild:self.world];
[self.world addChild:bottom];
[self.world addChild:self.player];
[self addChild:left];
[self addChild:right];
[self addChild:self.pause];
[self addChild:self.scoreLabelInGame];
[self addChild:self.actualScore];
}
-(void)createUI {
self.pause = [SKSpriteNode spriteNodeWithImageNamed:#"pausebutton.png"];
self.pause.size = CGSizeMake(self.customUnit,self.customUnit);
self.pause.name = #"pauseButton";
self.pause.position = CGPointMake(30, self.frame.size.height - 30);
self.scoreLabelInGame = [SKLabelNode labelNodeWithFontNamed:#"Futura"];
self.scoreLabelInGame.text = #"";
self.scoreLabelInGame.fontSize = 25;
self.scoreLabelInGame.position = CGPointMake(self.frame.size.width - 100, self.frame.size.height - 40);
self.actualScore = [SKLabelNode labelNodeWithFontNamed:#"Futura"];
self.actualScore.text = #"SCORE: 0";
self.actualScore.fontSize = 25;
self.actualScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeRight;
self.actualScore.position = CGPointMake(self.frame.size.width - 20, self.frame.size.height - 40);
self.deathImage = [SKSpriteNode spriteNodeWithImageNamed:#"youdied.png"];
self.deathImage.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)*1.5);
}
-(void)createPauseMenu {
self.pausedImage = [SKSpriteNode spriteNodeWithImageNamed:#"paused.png"];
self.pausedImage.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)*1.5);
self.restart = [SKLabelNode labelNodeWithFontNamed:#"Futura"];
self.restart.text = #"RESTART";
self.restart.fontSize = 25;
self.restart.position = CGPointMake(CGRectGetMidX(self.frame), self.pausedImage.position.y - self.pausedImage.position.y/5);
self.resume = [SKLabelNode labelNodeWithFontNamed:#"Futura"];
self.resume.text = #"RESUME";
self.resume.fontSize = 25;
self.resume.position = CGPointMake(self.restart.position.x, self.restart.position.y - self.customUnit);
}
-(void)spawningEnemy {
NSLog(#"spawned");
SKSpriteNode *aNewEnemy = [self.enemyData createEnemyWithSize:self.customUnit andWidth:self.frame.size.width andHeight:self.frame.size.height + self.player.position.y];
aNewEnemy.physicsBody.allowsRotation = NO;
aNewEnemy.physicsBody.categoryBitMask = self.enemyCategory;
aNewEnemy.physicsBody.collisionBitMask = self.enemyCategory | self.playerCategory | self.edgeCategory | self.bottomCategory;
aNewEnemy.physicsBody.contactTestBitMask = self.enemyCategory | self.playerCategory | self.edgeCategory | self.bottomCategory;
[self.world addChild:aNewEnemy];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if([self.pause containsPoint:location] && self.isPaused == NO){
[self pauseGame];
}else if([self.resume containsPoint:location] && self.isPaused == YES) {
[self resumeGame];
}else if ([self.restart containsPoint:location] && self.isPaused == YES){
[self restartGame];
}else if (self.isTouchingGround == YES && self.isPaused == NO) {
[self.playerData jump:self.player];
NSLog(#"GOD YES");
self.isTouchingGround = NO;
}
}
-(void)pauseGame {
[self createPauseMenu];
NSLog(#"Pausing...");
[self removeActionForKey:#"spawn"];
self.world.paused = YES;
[self addChild:self.pausedImage];
[self addChild:self.restart];
[self addChild:self.resume];
NSString *path = [NSString stringWithFormat:#"%#/menu_music.mp3", [[NSBundle mainBundle]resourcePath]];
NSURL *pauseMusicURL = [NSURL fileURLWithPath:path];
self.pauseMusicPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:pauseMusicURL error:nil];
self.pauseMusicPlayer.numberOfLoops = -1;
[self.pauseMusicPlayer play];
[self.pause removeFromParent];
self.scoreLabelInGame.position = CGPointMake(self.restart.position.x, self.resume.position.y - self.customUnit);
self.actualScore.position = CGPointMake(self.restart.position.x, self.scoreLabelInGame.position.y - self.customUnit);
self.isPaused = YES;
[self.mainMusicPlayer pause];
}
-(void)restartGame {
[self removeAllChildren];
[self removeAllActions];
self.enemyData = nil;
self.isPaused = NO;
[self.pauseMusicPlayer stop];
[self createSceneContents];
[self runAction:self.spawnAction withKey:#"spawn"];
}
-(void)resumeGame {
self.isPaused = NO;
[self.pauseMusicPlayer stop];
[self runAction:self.spawnAction withKey:#"spawn"];
self.scoreLabelInGame.position = CGPointMake(self.frame.size.width - 100, self.frame.size.height - 40);
self.actualScore.position = CGPointMake(self.frame.size.width - 20, self.frame.size.height - 40);
[self.mainMusicPlayer play];
[self.restart removeFromParent];
[self.resume removeFromParent];
[self.pausedImage removeFromParent];
[self addChild:self.pause];
}
-(void)gameOver {
NSLog(#"Game Over");
GameDataHelper *gameData = [[GameDataHelper alloc]init];
[self removeActionForKey:#"spawn"];
[self addChild:self.restart];
[self addChild:self.deathImage];
SKAction *gameOverSound = [SKAction playSoundFileNamed:#"gameover_tune.mp3" waitForCompletion:NO];
[self runAction:gameOverSound];
NSString *path = [NSString stringWithFormat:#"%#/menu_music.mp3", [[NSBundle mainBundle]resourcePath]];
NSURL *pauseMusicURL = [NSURL fileURLWithPath:path];
self.pauseMusicPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:pauseMusicURL error:nil];
self.pauseMusicPlayer.numberOfLoops = -1;
[self.pauseMusicPlayer play];
[self.pause removeFromParent];
SKLabelNode *highScore = [SKLabelNode labelNodeWithFontNamed:#"Futura"];
NSString *highScoreText = [NSString stringWithFormat:#"HIGHSCORE: %ld",[GameDataHelper sharedGameData].highScore];
highScore.text = highScoreText;
highScore.fontSize = 25;
highScore.position = CGPointMake(self.frame.size.width/2, self.restart.position.y - (2*self.customUnit));
[self addChild:highScore];
self.scoreLabelInGame.position = CGPointMake(self.restart.position.x, self.resume.position.y - self.customUnit);
self.actualScore.position = CGPointMake(self.restart.position.x, self.scoreLabelInGame.position.y - self.customUnit);
self.isPaused = YES;
[self.mainMusicPlayer pause];
[gameData save];
}
-(void)wentToForeground {
[self pauseGame];
}
In Enemy.m:
-(SKSpriteNode *)createEnemyWithSize:(float)size andWidth:(float)width andHeight:(float)height {
self.enemy = [SKSpriteNode spriteNodeWithImageNamed:#"block.png"];
self.enemy.size = CGSizeMake(size - 5, size - 5);
self.enemy.name = #"fallingEnemy";
self.enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(size - 3, size - 3)];
self.enemy.physicsBody.restitution = 0;
self.enemy.physicsBody.allowsRotation = NO;
int randomSection = arc4random_uniform(7);
switch (randomSection) {
case 0:
self.enemy.position = CGPointMake(2.5 + self.enemy.size.width/2, height-5);
break;
case 1:
self.enemy.position = CGPointMake(width/7 + self.enemy.size.width/2, height-5);
break;
case 2:
self.enemy.position = CGPointMake((width/7*2) + self.enemy.size.width/2, height-5);
break;
case 3:
self.enemy.position = CGPointMake((width/7*3) + self.enemy.size.width/2, height-5);
break;
case 4:
self.enemy.position = CGPointMake((width/7*4) + self.enemy.size.width/2, height-5);
break;
case 5:
self.enemy.position = CGPointMake((width/7*5) + self.enemy.size.width/2, height-5);
break;
case 6:
self.enemy.position = CGPointMake((width/7*6) + self.enemy.size.width/2, height-5);
break;
default:
break;
}
return self.enemy;
}
Even though you might have found the answer already i see some problems with your code:
Note: self.spawnAction needs to be a Strong property so maintain the reference when it's removed.
You are running the action on self.world, but removing it on self.
[self.world runAction:self.spawnAction withKey:#"spawn"];
[self removeActionForKey:#"spawn"];
self.world.paused = YES;
If you set the paused property of self.world to YES you do not need to remove the action as pause will immediately pause all actions.
You do not set the paused property to NO again on -(void)resumeGame
And you run it on self instead of self.world on resume.
Overall I would try to avoid using paused properties which might behave different and not give the results you want.
Also, keep in mind that removing nodes and actions don't happen instantly so if you pause nodes afterwards you might not get expected results.
Also, there is a limited amount of time you have on didEnterBackground to do your stuff before the it actually goes to background.
Hope it helps.
I am trying to add a few seconds to countdown timer each time when enemy and player node contacts.
Also when the player reach to some certain point I want player to pass to another level. I am sending part of the code . Could anybody help me to solve this problem. By the way because I am new to programming my code is a little hard to read . Sorry for that.
Thanks
-(void)update:(CFTimeInterval)currentTime{
if (startGamePlay){
startTime = currentTime;
startGamePlay = NO;
}
countDownInt = 10.0 - (int)(currentTime-startTime);
if(countDownInt > 0 ){ //if counting down to 0 show counter
countDown.text = [NSString stringWithFormat:#"%i", countDownInt];
}
else if (countDownInt == 0){
countDown.text =#"0";
Level2 *level2 = [Level2 sceneWithSize:self.frame.size];
SKTransition *transition = [SKTransition fadeWithDuration:0.5];
[self.view presentScene:level2 transition:transition];
}
}
- (void) didBeginContact:(SKPhysicsContact *)contact {
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
firstBody = contact.bodyA;
secondBody = contact.bodyB;
} else {
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
if ( firstBody.categoryBitMask == CollisionCategoryBrick && secondBody.categoryBitMask == CollisionCategoryShark ) {
NSLog(#"BRICK");
[contact.bodyB.node removeFromParent];
} else if ( firstBody.categoryBitMask == CollisionCategoryWaterBall && secondBody.categoryBitMask == CollisionCategoryShark ) {
NSLog(#"BALL");
countDownInt = [countDown.text intValue];
[contact.bodyA.node removeFromParent];
[self addPoints:PointsPerHit];
if (![ self childNodeWithName:#"WATERBALLTL"]) {
[self addWaterBallTopLeft];
}
if (![ self childNodeWithName:#"WATERBALLTR"]) {
[self addWaterBallTopRight];
}
if (![ self childNodeWithName:#"WATERBALLBL"]) {
[self addWaterBallBottomLeft];
}
if (![ self childNodeWithName:#"WATERBALLBR"]) {
[self addWaterBallBottomRight];
}
}
NSLog(#"%lu", (unsigned long)[self.children count]);
}
#import "HudNode.h"
#implementation HudNode
{
SKLabelNode *countDown;
BOOL startGamePlay;
NSTimeInterval startTime;
}
+ (instancetype) hudAtPosition:(CGPoint)position inFrame:(CGRect)frame {
HudNode *hud = [self node];
hud.position = position;
hud.zPosition = 10;
hud.name = #"HUD";
SKLabelNode *scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Futura-CondensedExtraBold"];
scoreLabel.name = #"Score";
scoreLabel.text = #"0";
scoreLabel.fontSize = 24;
scoreLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeRight;
scoreLabel.position = CGPointMake(frame.size.width-20, -10);
scoreLabel.zPosition = 12;
[hud addChild:scoreLabel];
SKLabelNode *countDown = [SKLabelNode labelNodeWithFontNamed:#"Futura-Medium"];
countDown.fontSize = 50;
countDown.position = CGPointMake(30, -10);
countDown.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter; //good for positioning with other sprites
countDown.fontColor = [SKColor whiteColor ];
countDown.name = #"countDown";
countDown.zPosition = 100;
[hud addChild:countDown];
return hud;
}
- (void) addPoints:(NSInteger)points {
self.score += points;
SKLabelNode *scoreLabel = (SKLabelNode *) [self childNodeWithName:#"Score"];
scoreLabel.text = [NSString stringWithFormat:#"Score:%li", (long)self.score];
}
Create a boolean flag that the update method checks to see if it should add seconds.
Add the following variable and set self.addSeconds = NO; initially:
#property (nonatomic) BOOL addSeconds;
Set self.addSeconds =YES; in the method where your player hits your enemy:
Add the following to the very beginning of the Update:
if(self.addSeconds == YES)
{
CountDownInt+= 5 //Change this to add as many seconds as you want
self.addSeconds=NO;
}
This should do the trick.
In this game I have asteroids flying down from to top of screen, and a ship you can move freely, but I have added some collision detection and it does not seem to work in the update method when I call [self scheduleupdate];
// Import the interfaces
#import "HelloWorldLayer.h"
// Needed to obtain the Navigation Controller
#import "AppDelegate.h"
#pragma mark - HelloWorldLayer
// HelloWorldLayer implementation
#implementation HelloWorldLayer
// Helper class method that creates a Scene with the HelloWorldLayer as the only child.
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// on "init" you need to initialize your instance
-(id) init
{
if( (self=[super init]) ) {
self.isTouchEnabled = YES;
moveLeft = NO;
moveRight = NO;
speed = 3;
fireSpeed = 8;
fireArray = [[NSMutableArray alloc] init];
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *bg = [[CCSprite alloc] initWithFile:#"space_bg.jpg"];
[bg setPosition:ccp(160, 240)];
CGSize imageSize = bg.contentSize;
bg.scaleX = winSize.width / imageSize.width;
bg.scaleY = winSize.height / imageSize.height;
bg.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:bg];
ship = [[CCSprite alloc] initWithFile:#"ship.png"];
[ship setPosition:ccp(100, 100)];
[self addChild:ship];
[self schedule:#selector(fireLoop:)];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(fireCreate)
userInfo:nil
repeats:YES];
asteroidArray = [[NSMutableArray alloc] init];
for(int i = 0; i < 100; ++i) {
CCSprite *asteroid = [[CCSprite alloc] initWithFile:#"asteroid1.png"];
[asteroidArray addObject:asteroid];
}
[self asteroidCreate];
[self scheduleUpdate];
}
return self;
}
CCSpriteBatchNode *spriteSheet;
NSMutableArray *asteroidAnimFrames;
- (float)randomValueBetween:(float)low andValue:(float)high {
return (((float) arc4random() / 0xFFFFFFFFu) * (high - low)) + low;
}
-(void)updtate:(ccTime)dt{
CGPoint shipPosition = [ship position];
for(int i = 0; i < asteroidArray.count; i++){
CCSprite *asteroid = [asteroidArray objectAtIndex:i];
if (CGRectIntersectsRect(ship.boundingBox, asteroid.boundingBox)) {
NSLog(#"hit");
}
}
}
- (void)countDownToCreateNextAsteroid {
int minTime = 1;
int maxTime = 10;
int randomTime = (arc4random() % (3));
id countdownDelay = [CCDelayTime actionWithDuration:randomTime];
id creationMethod = [CCCallFunc actionWithTarget:self selector:#selector(asteroidCreate)];
id countdownToCreateSeq = [CCSequence actions:countdownDelay, creationMethod, nil];
[self stopAllActions];
[self runAction:countdownToCreateSeq];
}
-(void)asteroidCreate {
CGSize winSize = [[CCDirector sharedDirector] winSize];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"asteroids.plist"];
spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"asteroids.png"];
asteroidAnimFrames = [NSMutableArray array];
for(int i=1; i <= 8; i++) {
[asteroidAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"asteroid%d.png", i]]];
}
CCAnimation *moveAsteroidAnim = [CCAnimation animationWithFrames:asteroidAnimFrames delay:0.1f];
CCSprite *asteroid = [CCSprite spriteWithSpriteFrameName:#"asteroid1.png"];
int x = arc4random() % 320;
int y = arc4random() % 480;
asteroid.position = ccp(x, 480);
CCAction *asteroidAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:moveAsteroidAnim restoreOriginalFrame:NO]];
[asteroidArray addObject:asteroid];
int q = arc4random() % 320;
int r = arc4random() % 10;
CCAction *moveAction = [CCMoveTo actionWithDuration:r position:ccp(q, -50)];
id asteroidRemove = [CCCallBlock actionWithBlock:^
{
[asteroid removeFromParentAndCleanup:YES];
[asteroidArray removeObject:asteroid];
}];
id asteroidSeq = [CCSequence actions:moveAction, asteroidRemove, nil];
[asteroid runAction:asteroidSeq];
[asteroid runAction:asteroidAction];
[spriteSheet addChild:asteroid];
[self addChild:spriteSheet];
[self countDownToCreateNextAsteroid];
}
-(void)fireLoop:(ccTime)fl {
if(fireArray.count > 0){
for(int i = 0; i < fireArray.count; i++){
CCSprite *tmpFire = [fireArray objectAtIndex:i];
if(tmpFire.position.y < 500){
[tmpFire setPosition:ccp([tmpFire position].x, [tmpFire position].y + fireSpeed)];
}else{
[fireArray removeObjectAtIndex:i];
}
}
} else {
}
}
-(void)fireCreate{
int shootPositionX = [ship position].x;
int shootPositionY = ([ship position].y) + 35;
CCSprite *fire;
fire = [[CCSprite alloc] initWithFile:#"fire.png"];
[fire setPosition:ccp(shootPositionX, shootPositionY)];
[fireArray addObject:fire];
[self addChild:fire];
[fire release];
}
-(void)gameLoop:(ccTime)dt {
int shipPositionX = 41/2;
if([ship position].x > shipPositionX){
[ship setPosition:ccp([ship position].x - speed, [ship position].y)];
}
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for(UITouch *t in touches){
CGPoint point = [self convertTouchToNodeSpace:t];
//if(point.x <= 160){
// moveRight = NO;
// moveLeft = YES;
//}else{
// moveRight =YES;
// moveLeft = NO;
//}
if(allowedToMove)
[ship setPosition:ccp(point.x, point.y + 76)];
}
}
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for(UITouch *t in touches){
CGPoint point = [self convertTouchToNodeSpace:t];
int shipX = [ship position].x;
int shipY = [ship position].y;
if (CGRectContainsPoint(CGRectMake (shipX - 20.5, shipY - 96, 50, 50), point))
{
allowedToMove = true;
}
}
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
for(UITouch *t in touches){
CGPoint point = [self convertTouchToNodeSpace:t];
allowedToMove = false;
}
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
// don't forget to call "super dealloc"
[super dealloc];
}
#pragma mark GameKit delegate
-(void) achievementViewControllerDidFinish:(GKAchievementViewController *)viewController
{
AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
[[app navController] dismissModalViewControllerAnimated:YES];
}
-(void) leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
[[app navController] dismissModalViewControllerAnimated:YES];
}
#end
I am trying to get the value from my custom class SKNode object. The problem is when I touch on the object no matter what is gives me the same value regardless of the object I touch on.
(blue button) and I cannot get the buttonID,buttonType that I set earlier.
Everything works well, except when I need to get the buttonType, buttonID of the object I touch or drag over.
I am not sure where I am going wrong, any help or push in the right direction would be great. Thanks.
here is my custom class .h file.
#import <SpriteKit/SpriteKit.h>
#interface ButtonNode : SKNode {
SKNode *buttonCustom;
}
#property int buttonType, buttonColumn, buttonID, xPos, yPos;
#property NSString *buttonName;
-(id)initWithButtonType:(int)buttonType;
#end
Here is my custom class .m file
#import "ButtonNode.h"
#define kBoxSize CGSizeMake(40, 40)
#implementation ButtonNode
#synthesize buttonColumn,buttonType,buttonID,xPos,yPos,buttonName;
static const uint32_t blueCategory = 1 << 0;
static const uint32_t redCategory = 1 << 1;
static const uint32_t greenCategory = 1 << 2;
static const uint32_t yellowCategory = 1 << 3;
-(id)initWithButtonType:(int)buttonType {
self = [super init];
if (buttonType == 1) {
NSLog(#"BLUE BUTTON CREATE");
[self addButtonBlue];
}
if (buttonType == 2) {
NSLog(#"RED BUTTON CREATE");
[self addButtonRed];
}
if (buttonType == 3) {
NSLog(#"Green BUTTON CREATE");
[self addButtonGreen];
}
if (buttonType == 4) {
NSLog(#"Yellow BUTTON CREATE");
[self addButtonYellow];
}
return self;
}
- (void) addButtonBlue {
SKSpriteNode *rect;
//button type 1
rect = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:kBoxSize];
int tmpInt = [[NSDate date] timeIntervalSince1970];
NSString *tmpName = [NSString stringWithFormat:#"%i", tmpInt];
rect.name = tmpName; //unique name.
rect.name = #"1";
rect.physicsBody.categoryBitMask = blueCategory;
rect.physicsBody.contactTestBitMask = blueCategory;
rect.physicsBody.collisionBitMask = blueCategory | redCategory | yellowCategory | greenCategory;
rect.position = CGPointMake(xPos , yPos );
[self addChild:rect];
}
- (void) addButtonRed {
SKSpriteNode *rect;
//button type 2
rect = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:kBoxSize];
int tmpInt = [[NSDate date] timeIntervalSince1970];
NSString *tmpName = [NSString stringWithFormat:#"%i", tmpInt];
rect.name = tmpName; //unique name.
rect.name = #"2";
rect.physicsBody.categoryBitMask = redCategory;
rect.physicsBody.contactTestBitMask = redCategory;
rect.physicsBody.collisionBitMask = blueCategory | redCategory | yellowCategory | greenCategory;
rect.position = CGPointMake(xPos , yPos );
[self addChild:rect];
}
- (void) addButtonGreen {
SKSpriteNode *rect;
//button type 3
rect = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:kBoxSize];
int tmpInt = [[NSDate date] timeIntervalSince1970];
NSString *tmpName = [NSString stringWithFormat:#"%i", tmpInt];
rect.name = tmpName; //unique name.
rect.name = #"3";
rect.physicsBody.categoryBitMask = greenCategory;
rect.physicsBody.contactTestBitMask = greenCategory;
rect.physicsBody.collisionBitMask = blueCategory | redCategory | yellowCategory | greenCategory;
rect.position = CGPointMake(xPos , yPos );
[self addChild:rect];
}
- (void) addButtonYellow {
SKSpriteNode *rect;
//button type 4
rect = [SKSpriteNode spriteNodeWithColor:[UIColor yellowColor] size:kBoxSize];
int tmpInt = [[NSDate date] timeIntervalSince1970];
NSString *tmpName = [NSString stringWithFormat:#"%i", tmpInt];
rect.name = tmpName; //unique name.
rect.name = #"4";
rect.physicsBody.mass = 1;
rect.physicsBody.categoryBitMask = yellowCategory;
rect.physicsBody.contactTestBitMask = yellowCategory;
rect.physicsBody.collisionBitMask = blueCategory | redCategory | yellowCategory | greenCategory;
rect.position = CGPointMake(xPos , yPos );
[self addChild:rect];
}
#end
Here is where I create the buttons.
(at top of file with rest of global ivar )
ButtonNode * newButton;
for (int i = 1; i <= 6; i++) {
//create random Int
int tmpInt = arc4random() %3;
NSLog(#"tmp %i" ,tmpInt);
column1.position = CGPointMake(100, self.frame.size.height - 40);
if (tmpInt == 0) {
//button type 1
newButton = [[ButtonNode alloc] initWithButtonType:1];
newButton.xPos = column1.position.x;
newButton.yPos = column1.position.y *i;
newButton.buttonID = 344224351; //unique name
newButton.buttonColumn = 2;
newButton.buttonType = 1;
[column1 addChild:newButton];
blueTotal++;
totalButtons++;
column1Total++;
}
if (tmpInt == 1) {
//button type 2
newButton = [[ButtonNode alloc] initWithButtonType:2];
newButton.xPos = column1.position.x;
newButton.yPos = column1.position.y *i;
newButton.buttonID = 344224351; //unique name
newButton.buttonColumn = 2;
newButton.buttonType = 1;
[column1 addChild:newButton];
redTotal++;
totalButtons++;
column1Total++;
}
}
Here is the Part that is not working correctly.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
UITouch* touch = [touches anyObject];
CGPoint loc = [touch locationInNode:self];
NSArray *nodes = [self nodesAtPoint:loc];
for (SKNode *nod in nodes) {
NSString *tmp = nod.name;
if (tmp.length !=0) {
NSString * tmpType = nod.name;
if ([tmpType isEqualToString:#"1"]) {
NSLog(#"Node Type: %#", nod.name);
previousButton = #"1";
NSLog (#"%d",newButton.buttonType);
}
if ([tmpType isEqualToString:#"2"]) {
NSLog(#"Node Type: %#", nod.name);
previousButton = #"2";
NSLog (#"%d",newButton.buttonType);
}
if ([tmpType isEqualToString:#"3"]) {
NSLog(#"Node Type: %#", nod.name);
previousButton = #"3";
NSLog (#"%d",newButton.buttonType);
}
if ([tmpType isEqualToString:#"4"]) {
NSLog(#"Node Type: %#", nod.name);
previousButton = #"4";
NSLog (#"%d",newButton.buttonType);
}
}
}
}
}
A SKNode does not have those properties.
Try this just inside your for loop :
ButtonNode *myButton = (ButtonNode *)nod;
That will cast nod correctly as a ButtonNode, and you can use myButton like this :
NSLog(#"%d",myButton.buttonType);
Then you should be able to access the properties you have defined in the ButtonNode class.
You might only want to do that cast if you are sure it's a ButtonNode, but was just trying to help you understand why those properties would NEVER be accessible given your current code.
Also, your usage of newButton in that loop in touchesBegan is not what I think you 'think' it is. It's going to be the last button created, not the current node being stored in nod in the loop.
I'm new to cocos2d so excuse my ignorance, but I would like to know how to detect when a sprite has been touched and call a method when it has been touched.
I've defined and added my sprite like this:
CCSprite *infoButton = [CCSprite spriteWithFile: #"info.png"];
[infoButton setPosition:CGPointMake(450, 290)];
[menuBG addChild:infoButton];
I've followed various resources but they have been very vague, most of which the sprite was set in its own class.
Thanks in advance.
In regular Cocos2D:
-(void) ccTouchesBegan:(NSSet*)touches withEvent:(id)event
{
CCDirector* director = [CCDirector sharedDirector];
UITouch* touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:director.openGLView];
CGPoint locationGL = [director convertToGL:touchLocation];
CGPoint locationInNodeSpace = [infoButton convertToNodeSpace:locationGL];
CGRect bbox = CGRectMake(0, 0,
infoButton.contentSize.width,
infoButton.contentSize.height);
if (CGRectContainsPoint(bbox, locationInNodeSpace))
{
// code for when user touched infoButton sprite goes here ...
}
}
To demonstrate how much Kobold2D simplifies this over Cocos2D's approach:
-(void) update:(ccTime)delta
{
KKInput* input = [KKInput sharedInput];
if ([input isAnyTouchOnNode:infoButton touchPhase:KKTouchPhaseBegan])
{
// code for when user touched infoButton sprite goes here ...
}
}
Why dont you use CCMenuItemImage?
CCMenuItemImage* info = [CCMenuItemImage itemFromNormalImage:#"info.png" selectedImage:#"info.png" target:self selector:#selector(pressed:)];
CCMenu* menu = [CCMenu menuWithItems:info, nil];
menu.position = ccp(450,290);
[menuBG addChild:menu];
and another function whenever the user pressed the button..
-(void)pressed:(id)sender
{
// whatever you would like to do here...
}
The solution depends on your code architecture. For menu items use xuanweng variant. Alternatively you may check intersection of touch point with sprite bounds in ccTouchBegan method of parent layer. You need to transform touch point to layer space (in common case this transform is identity) and check CGRectContainsPoint ([sprite boundingBox], touchPos)
I made this custom event listener a while ago
This is the CCNode+events.h file(the header file)
//
// CCNode+events.h
// Save the world´s
//
// Created by Sebastian Winbladh on 2013-10-14.
// Copyright (c) 2013 Sebastian Winbladh. All rights reserved.
//
#import "cocos2d.h"
#import <objc/runtime.h>
//We are using CCLayer so we can capture events that occurs on top of it
#interface EventLayer : CCLayer
#property (nonatomic,assign) NSMutableArray *nodes;
#property (nonatomic,assign) void (^callback)(NSArray*nodeArray,NSSet*touches,NSString *event);
+(id)sharedEventLayer:(CCNode *)on callback:(void(^)(NSArray*nodeArray,NSSet*touches,NSString *event))block node:(NSArray *)addNode;
#end
#interface CCNode (props)
#property (nonatimic,assign) id rotationCX;
#property (nonatomic,assign) id rotationCY;
#property (nonatomic,assign) id scaleCX;
#property (nonatomic,assign) id scaleCY;
#end
//Sprite category
//Used to capture sprite cords and eval events
#interface CCNode (events)
-(void)addEventWithEvent:(NSString *)event callback:(void(^)(CCNode*node))back useDispatcher:(BOOL)disp;
#end
This is the CCNode+events.m file(Main file)
//
// Created by Sebastian Winbladh on 2013-10-14.
// Copyright (c) 2013 Sebastian Winbladh. All rights reserved.
//
#import "CCNode+events.h"
#implementation EventLayer
#synthesize callback,nodes;
//Shared instance
+(id)sharedEventLayer:(CCNode *)on callback:(void (^)(NSArray*nodeArray,NSSet*touches,NSString *event))block node:(NSArray *)addNode{
static dispatch_once_t onceToken;
static EventLayer *eventLayer;
dispatch_once(&onceToken, ^{
eventLayer = [[[EventLayer alloc]init]autorelease];
eventLayer.callback = block;
[[eventLayer getParent:on] addChild:eventLayer];
});
[eventLayer.nodes addObject:addNode];
return eventLayer;
}
//Find top level parent child
-(id)getParent:(CCNode*)on{
id ret=on;
BOOL done=false;
while(done == false){
ret = [ret parent];
if(![[ret parent] children]){
done = true;
}
}return ret;
}
-(void)callbackWithEvent:(NSString*)event nsSet:(NSSet *)set{
for(NSArray *lNodeArray in nodes){
self.callback(lNodeArray,set,event);
}
}
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self callbackWithEvent:#"touchBegan" nsSet:touches];
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[self callbackWithEvent:#"touchEnded" nsSet:touches];
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[self callbackWithEvent:#"touchDrag" nsSet:touches];
}
//Initilize
-(id)init{
if(self = [super init]){
[self setTouchEnabled:YES];
nodes = [[NSMutableArray alloc]init];
}
return self;
}
-(void)dealloc{
//Dealloc nodes
[nodes release];
nodes = nil;
[super dealloc];
}
#end
#implementation CCNode (props)
#dynamic rotationCX,rotationCY,scaleCX,scaleCY;
-(void)setRotationCX:(id)rotationCX{
objc_setAssociatedObject(self, #selector(rotationCX), rotationCX, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(id)rotationCX{return objc_getAssociatedObject(self, #selector(rotationCX));}
-(void)setRotationCY:(id)rotationCY{
objc_setAssociatedObject(self, #selector(rotationCY), rotationCY, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(id)rotationCY{return objc_getAssociatedObject(self, #selector(rotationCY));}
//Scales
-(void)setScaleCX:(id)scaleCX{
objc_setAssociatedObject(self, #selector(scaleCX), scaleCX, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(id)scaleCX{return objc_getAssociatedObject(self, #selector(scaleCX));}
-(void)setScaleCY:(id)scaleCY{
objc_setAssociatedObject(self, #selector(scaleCY), scaleCY, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(id)scaleCY{return objc_getAssociatedObject(self, #selector(scaleCY));}
#end
#implementation CCNode (events)
-(void)createEventLayerWithEvent:(void(^)(NSArray*nodeArray,NSSet*touches,NSString *event))block node:(NSArray *)addNode{
[EventLayer sharedEventLayer:self callback:block node:addNode];
}
//Get top level child parent
-(id)getParent:(CCNode*)on{
id ret=on;
BOOL done=false;
while(done == false){
ret = [ret parent];
if(![[ret parent] children]){
done = true;
}
}return ret;
}
//This function creates a custom bounding box.
//It takes all childrens in the loop and calculate widths, hights, anchorPoints, positions, scales and rotations
//to get the exact bounding box of the node.
-(void)toggleRotationOnItems:(NSMutableArray *)items func:(NSString*)type{
for(NSArray *item in items){
CCNode *innerItems=[item objectAtIndex:0];
if([type isEqualToString:#"zero"]){
innerItems.rotationX=0;
innerItems.rotationY=0;
}
if([type isEqualToString:#"reset"]){
innerItems.rotationX=((NSNumber*)innerItems.rotationCX).floatValue;
innerItems.rotationY=((NSNumber*)innerItems.rotationCY ).floatValue;
}
}
}
-(CGPoint)getScalesOnChild:(CCNode *)item mother:(CCNode *)items{
CCNode *i=item;
BOOL didFinish=false;
CGPoint scales;
scales.x = item.scaleX;
scales.y = item.scaleY;
while(didFinish == false){
if([i isEqual:items])didFinish=true;
i = [i parent];
scales.x *= i.scaleX;
scales.y *= i.scaleY;
}
return scales;
}
-(BOOL)isVisible:(CCNode*)node mother:(CCNode*)m{
CCNode *i=node;
BOOL didFinish=false;
while(didFinish == false){
if(i.visible == false){
return false;
continue;
}
if([i isEqual:m])didFinish=true;
i = [i parent];
}
return true;
}
-(NSMutableArray*)createBoundingBox:(CCNode *)node{
node.rotationCX = [NSNumber numberWithFloat:node.rotationY ];
node.rotationCY = [NSNumber numberWithFloat:node.rotationY ];
node.scaleCX = [NSNumber numberWithFloat:node.scaleX ];
node.scaleCY = [NSNumber numberWithFloat:node.scaleY];
NSMutableArray *l=[[[NSMutableArray alloc]initWithObjects:node, nil]autorelease];
int c=1;
NSMutableArray *ret=[[[NSMutableArray alloc]init]autorelease];
if(node.visible == true)ret=[[[NSMutableArray alloc]initWithObject:[NSArray arrayWithObjects:node,nil]]autorelease];
//This first loop will loop until the count var is stable//
for(int r=0;r<c;r++){
//This loop will loop thru the child element list//
for(int z=0;z<[[l objectAtIndex:r] children].count;z++){
//Push the element to the return array.
CCNode *nodeItem = ((CCNode*)[[[l objectAtIndex:r] children] objectAtIndex:z]);
nodeItem.rotationCX = [NSNumber numberWithFloat:nodeItem.rotationX ];
nodeItem.rotationCY = [NSNumber numberWithFloat:nodeItem.rotationY ];
nodeItem.scaleCX = [NSNumber numberWithFloat:nodeItem.scaleX ];
nodeItem.scaleCY = [NSNumber numberWithFloat:nodeItem.scaleY];
if([self isVisible:nodeItem mother:node])[ret addObject:[NSArray arrayWithObjects:nodeItem, nil]];
if([[[[[l objectAtIndex:r] children] objectAtIndex:z] children] objectAtIndex:0]){
[l addObject:[[[l objectAtIndex:r] children] objectAtIndex:z]];
c++;
}//IF
}//FOR
}//FOR
NSMutableArray *statickPoints = [[[NSMutableArray alloc]init]autorelease];
NSMutableArray *dynamicPoints = [[[NSMutableArray alloc]init]autorelease];
//Set the rotation to 0 so we can calculate the values better
[self toggleRotationOnItems:ret func:#"zero"];
for(NSArray *items in ret){
//Create variables to hold the node point and the item it self
CGPoint nodePoint;
CCNode *innerItems=[items objectAtIndex:0];
//Check wich node world we will use
nodePoint = [[innerItems parent] convertToWorldSpace:innerItems.position];
CGPoint scales=[self getScalesOnChild:innerItems mother:node];
float widthOffsetP1 = innerItems.contentSize.width*innerItems.anchorPoint.x*scales.x;
float heightOffsetP1 = innerItems.contentSize.height*innerItems.anchorPoint.y*scales.y;
float widthOffsetP1Flip = innerItems.contentSize.width*(1-innerItems.anchorPoint.x)*scales.x;
float heightOffsetP1Flip = innerItems.contentSize.height*(1-innerItems.anchorPoint.y)*scales.y;
//statick positions
CGPoint point1 = CGPointMake(nodePoint.x-widthOffsetP1,nodePoint.y+heightOffsetP1Flip);
CGPoint point2 = CGPointMake(nodePoint.x-widthOffsetP1+innerItems.contentSize.width*scales.x,
nodePoint.y-heightOffsetP1+innerItems.contentSize.height*scales.y);
CGPoint point3 = CGPointMake(nodePoint.x-widthOffsetP1+innerItems.contentSize.width*scales.x,
nodePoint.y-heightOffsetP1);
CGPoint point4 = CGPointMake(nodePoint.x-widthOffsetP1,nodePoint.y-heightOffsetP1);
//Append to array
[statickPoints addObject:[NSArray arrayWithObjects:innerItems,
[NSValue valueWithCGPoint:point1],
[NSValue valueWithCGPoint:point2],
[NSValue valueWithCGPoint:point3],
[NSValue valueWithCGPoint:point4],nil]];
}
//Callculate mother and child rotations
for(NSArray *items in statickPoints){
NSValue *point1 = [items objectAtIndex:1];
NSValue *point2 = [items objectAtIndex:2];
NSValue *point3 = [items objectAtIndex:3];
NSValue *point4 = [items objectAtIndex:4];
int matrix_length=3;
CGPoint points[matrix_length];
points[0] = [point1 CGPointValue];
points[1] = [point2 CGPointValue];
points[2] = [point3 CGPointValue];
points[3] = [point4 CGPointValue];
// Seting the statick positions to the rotations
for(int i=0;i<=matrix_length;i++){
CGPoint nodePoint;
CCNode *item = [items objectAtIndex:0];
BOOL didFinish = false;
while(didFinish == false){
nodePoint = [[item parent] convertToWorldSpace:item.position];
float widthOffsetP1 = (points[i].x - (nodePoint.x));
float heightOffsetP1 = (points[i].y - (nodePoint.y));
float radians1=sqrt(fabs(powf(widthOffsetP1, 2))+fabs(powf(heightOffsetP1,2)));
float newRotation1 =CC_RADIANS_TO_DEGREES(atan2(widthOffsetP1,heightOffsetP1)) + ((NSNumber*)item.rotationCX).floatValue ;
float p1RotApplyed=(radians1) * sinf(CC_DEGREES_TO_RADIANS(newRotation1));
float p2RotApplyed=(radians1) * cosf(CC_DEGREES_TO_RADIANS(newRotation1));
points[i].x-=-p1RotApplyed+(widthOffsetP1);
points[i].y-=-p2RotApplyed+(heightOffsetP1);
if([item isEqual:node]){
didFinish=true;
}
item = [item parent];
}
}
[dynamicPoints addObject:[NSArray arrayWithObjects:[NSValue valueWithCGPoint:points[0]],
[NSValue valueWithCGPoint:points[1]],
[NSValue valueWithCGPoint:points[2]],
[NSValue valueWithCGPoint:points[3]],
nil]];
/* CCLabelTTF *la=[CCLabelTTF labelWithString:#"O" fontName:#"Arial" fontSize:6];
la.anchorPoint=ccp(0.5,0.5);
la.position=points[3];
[[self getParent:node ]addChild:la];
CCLabelTTF *la1=[CCLabelTTF labelWithString:#"O" fontName:#"Arial" fontSize:6];
la1.anchorPoint=ccp(0.5,0.5);
la1.position=points[2];
[[self getParent:node ]addChild:la1];
CCLabelTTF *la2=[CCLabelTTF labelWithString:#"O" fontName:#"Arial" fontSize:6];
la2.anchorPoint=ccp(0.5,0.5);
la2.position=points[1];
[[self getParent:node ]addChild:la2];
CCLabelTTF *la3=[CCLabelTTF labelWithString:#"O" fontName:#"Arial" fontSize:6];
la3.anchorPoint=ccp(0.5,0.5);
la3.position=points[0];
[[self getParent:node ]addChild:la3];*/
}
//Reset rotations
[self toggleRotationOnItems:ret func:#"reset"];
return dynamicPoints;
}
-(BOOL)boxContainsPoint:(CGPoint)p box:(NSMutableArray*)a test:(CCNode*)t{
BOOL returns=false;
NSMutableArray *ret=[[[NSMutableArray alloc]init]autorelease];
for(NSArray *items in a){
NSValue *point1 = [items objectAtIndex:0];
NSValue *point2 = [items objectAtIndex:1];
NSValue *point3 = [items objectAtIndex:2];
NSValue *point4 = [items objectAtIndex:3];
int matrix_length=4;
CGPoint points[matrix_length*2+1];
points[8] = points[4] = points[0] = [point1 CGPointValue];
points[5] = points[1] = [point2 CGPointValue];
points[6] = points[2] = [point3 CGPointValue];
points[7] = points[3] = [point4 CGPointValue];
NSMutableArray *hits=[[[NSMutableArray alloc]init]autorelease];
int p1=0;
float max=0;
for(int i=0;i<=matrix_length;i++){if(points[i].y>=max)p1=i;max=points[i].y;}
for(int i=0;i<matrix_length;i+=2){
CGPoint graphOrigo = ccp(points[p1+i+1].x,points[p1+i].y);
double x = (graphOrigo.x-p.x);
double k = (graphOrigo.y-points[p1+i+1].y)/(graphOrigo.x-points[p1+i].x);
double m = (graphOrigo.y-points[p1+i+1].y);
double y = (-k*x+m);
if((graphOrigo.y-p.y)>(y) && i <=1){
[hits addObject:[NSNumber numberWithBool:YES]];
}else if((graphOrigo.y-p.y)<(y) && i >=1){
[hits addObject:[NSNumber numberWithBool:YES]];
}else{
[hits addObject:[NSNumber numberWithBool:NO]];
}
graphOrigo = ccp(points[p1+i+1].x,points[p1+i+2].y);
y = (graphOrigo.y-p.y);
k = (graphOrigo.x-points[p1+i+2].x)/(graphOrigo.y-points[p1+i+1].y);
m = (graphOrigo.x-points[p1+i+2].x);
x = (-k*y+m);
if((graphOrigo.x-p.x)>(x) && i <=1){
[hits addObject:[NSNumber numberWithBool:YES]];
}else if((graphOrigo.x-p.x)<(x) && i >=1){
[hits addObject:[NSNumber numberWithBool:YES]];
}else{
[hits addObject:[NSNumber numberWithBool:NO]];
}
}
BOOL hit=YES;
for(NSNumber *bools in hits){
if(bools.boolValue == NO){
hit=NO;
}
}
[ret addObject:[NSNumber numberWithBool:hit]];
}
for(NSNumber *b in ret){
if(b.boolValue == YES){
returns=true;
}
}
return returns;
}
-(BOOL)validateToush:(NSSet *)touches nodePoint:(CCNode *)node{
UITouch *touch = [touches anyObject];
id parent = [self getParent:self];
//Touch to global node space
CGPoint touchPoint = [parent convertTouchToNodeSpace:touch];
NSMutableArray *nodeBox = [self createBoundingBox:(CCNode *)node];
//Validating of hit point
if([self boxContainsPoint:touchPoint box:nodeBox test:node])return true;
return false;
}
-(void)addEventWithEvent:(NSString *)event callback:(void (^)(CCNode*node))back useDispatcher:(BOOL)disp{
//Add a cc layer so we can capture toushes
[self createEventLayerWithEvent:^(NSArray*nodeArray,NSSet*touches,NSString *event) {
//Calback block
NSArray *lNodeArray=nodeArray;
CCNode *lNode = [lNodeArray objectAtIndex:0];
void(^nodeBack)(CCNode*node) =[nodeArray objectAtIndex:2];
BOOL disp =((NSNumber *)[nodeArray objectAtIndex:3]).boolValue;
if([[lNodeArray objectAtIndex:1] isEqualToString:#"touchBegan"]){
//Return to callback block
if([event isEqualToString:#"touchBegan"] && [lNode validateToush:touches nodePoint:lNode] || disp==NO && [event isEqualToString:#"touchBegan"])nodeBack((CCNode*)[nodeArray objectAtIndex:0]);
}else if([[lNodeArray objectAtIndex:1] isEqualToString:#"touchEnded"]){
//Return to callback block
if([event isEqualToString:#"touchEnded"] && [lNode validateToush:touches nodePoint:lNode] || disp==NO && [event isEqualToString:#"touchEnded"])nodeBack((CCNode*)[nodeArray objectAtIndex:0]);
}else if([[lNodeArray objectAtIndex:1]isEqualToString:#"touchDrag"]){
//Return to callback block
if([event isEqualToString:#"touchDrag"] && [lNode validateToush:touches nodePoint:lNode] || disp==NO && [event isEqualToString:#"touchDrag"])nodeBack((CCNode*)[nodeArray objectAtIndex:0]);
}
} node:[NSArray arrayWithObjects:self,event,Block_copy(back),[NSNumber numberWithBool:disp], nil]];
}
#end
To use this event listener is very simple
Include the CCSprite+events.h file in your project.
Create a CCNode/CCSprite(yourNode) that you like to add an eventlistener on.
Then your create the event by coding this
[yourNode addEventWithEvent:#"touchBegan" callback:^(CCNode *node) {
NSLog(#"Touch began on node");
} useDispatcher:YES];
The addEventWithEvent parameter takes three types
touchBegan = fired when your finger touches the node
touchEnded = fired when your finger releases the node
touchDrag == fired when moving you finger on the node
The callback takes a callback block that will be fired on the event above.
The useDispatcher takes a BOOL value(YES or NO).
If it get´s set to YES the event will fire on the CCNode.
If it get´s set to NO the event will fire on the screen