I am creating a small game where objective is to tap and destroy mouse. I created a separate mouse class for it.
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "HelloWorldLayer.h"
#interface Mouse : CCNode <CCTargetedTouchDelegate> {
CCSprite *sprite;
HelloWorldLayer *HelloLayer;
}
-(id) initWithGame:(HelloWorldLayer *)aGame;
-(void) runFloatAction;
#property(nonatomic, retain) CCSprite *sprite;
#property(nonatomic, retain) HelloWorldLayer *HelloLayer;
#end
I am initializing like this in .m file:
-(id) initWithGame:(HelloWorldLayer *)aGame{
if ((self = [super init])) {
self.sprite = [CCSprite spriteWithFile:#"mouse.png"];
self.sprite.scale = 0.3f + CCRANDOM_0_1() * 0.5f;
self.sprite.position = ccp(CCRANDOM_0_1() * 480, CCRANDOM_0_1() * 320);
self.HelloLayer = aGame;
[aGame addChild:sprite];
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self
priority:1
swallowsTouches:YES];
//[self runFloatAction];
}
return (self);
}
I want to remove sprite on tap. For which I am using this code in .m file: -
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
if ([self containsTouchLocation:touch]) {
[self.sprite removeFromParentAndCleanup:YES];
return YES;
}else{
return NO;
}
}
Unfortunately I am not able to remove sprite. Logically, we have to remove sprite from parent. But, its not working in actual.
The way I structure my classes is to have the Mouse class as a subclass of CCSprite. If you handle the touch events in the main game class than you just remove the mouse. You also need to enable touch events if you haven't done that.
I recommend you do the above and put this in your game class.
[self setIsTouchEnabled:YES];
Mouse *myMouse = [Mouse spriteWithImage:#"Mouse.png"];
[myMouse setPosition:CGPointMake(160, 240)];
[self addChild:myMouse];
Then just handle the touch events in your game class.
Related
I have a problem in using touches in my scene.
I’ ve created a sprite (player.ccb) working in Sprite Builder that has a name =player in CCnode section.
Here it is the main code written in GameScene :
So after opening the simulator nothing doesn’t happen and in the Debug area there is nothing written.
Thank you in advance for your help!
//
// GameScene.m
// MIOGIOCO18
//
// Created by Fabio Tavanti on 12/12/15.
// Copyright (c) 2015 Apportable. All rights reserved.
//
#import "GameScene.h"
#implementation GameScene
{
__weak CCNode* _levelNode;
__weak CCPhysicsNode* _physicsNode;
__weak CCNode* _playerNode;
__weak CCNode* _backgroundNode;
}
-(void) didLoadFromCCB
{
// enable receiving input events
self.userInteractionEnabled = YES;
// load the current level
[self loadLevelNamed:nil];
}
-(void) loadLevelNamed:(NSString*)levelCCB
{
// get the current level's player in the scene by searching for it recursively
_playerNode = [self getChildByName:#"player" recursively:YES];
NSAssert1(_playerNode, #"player node not found in level: %#", levelCCB);
}
//-(void) touchBegan:(CCTouch *)touch withEvent:(UIEvent *)event
-(void) touchBegan:(CCTouch *)touch withEvent:(CCTouchEvent *)event
{
NSLog(#"okaay pressed");
_playerNode.position = [touch locationInNode:self];
}
#end
I don't know how you structured your ccb file and if you made proper relation to your actual GameScene, so best thing for you would be to put
self.userInteractionEnabled = YES;
in the GameScene's onEnter method...
I am working on a game that has the player controlling a spaceShip. I want to make it such that if the spaceShip sprite collides with spaceJunk the junk disappears.
Here is my code so far.
HelloWorldLayer.h
#import <GameKit/GameKit.h>
// HelloWorldLayer
#interface HelloWorldLayer : CCLayerColor
{
CCSprite *_starShip;
CCSprite *_Paddle1;
CCSprite *_paddle2;
}
// returns a CCScene that contains the HelloWorldLayer as the only child
+(CCScene *) scene;
#end
HelloWorldLayer.M
// Import the interfaces
#import "HelloWorldLayer.h"
// Needed to obtain the Navigation Controller
#import "AppDelegate.h"
#pragma mark - HelloWorldLayer
// HelloWorldLayer implementation
//Import SpaceThings
#import "SpaceThings.h"
#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;
}
-(void)gameLgoic:(ccTime)dt
{
[self addSpaceThings];
}
-(void) addSpaceThings
{
// _junk = [CCSprite spriteWithFile:#"catplaceholder.png"];
SpaceThings * spaceThings = nil;
if (arc4random() % 2 == 0){
spaceThings = [[[Astroids alloc] init] autorelease];
}else{
spaceThings = [[[SpaceJunk alloc]init] autorelease];
}
//determine where to spawn the space junk along the X-axis
CGSize winSize = [CCDirector sharedDirector].winSize;
int minX = spaceThings.contentSize.width/2;
int maxX = winSize.width - spaceThings.contentSize.width/2;
int rangeX =maxX - minX;
int actualX = (arc4random() % rangeX) + minX;
//spawn the sprite slightly above the screen
spaceThings.position = ccp(actualX, winSize.height+_starShip.contentSize.height/2);
[self addChild:spaceThings];
//set the speed of junk
int minDuration = spaceThings.minMoveDirection;
int maxDuarton = spaceThings.maxMoveDirection;
int rangeDuration = maxDuarton - minDuration;
float actualDuraton = (arc4random() % rangeDuration)+ minDuration;
//move junk logic
CCMoveTo * actionMove = [CCMoveTo actionWithDuration:actualDuraton position:ccp(actualX, -spaceThings.contentSize.height/2)];
CCCallBlockN *actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node){[node removeFromParentAndCleanup:YES];}];
[spaceThings runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
if (CGRectIntersectsRect(_starShip.boundingBox, spaceThings.boundingBox)){
[self removeChild:spaceThings cleanup:YES];
}
}
// on "init" you need to initialize your instance
-(id) init
{
if (self =[super initWithColor:ccc4(255,255,255,255)]){
CGSize winSize = [CCDirector sharedDirector].winSize;
_starShip = [CCSprite spriteWithFile:#"theShip.gif"];
_starShip.position = ccp(winSize.width/2, 1.25*_starShip.contentSize.height);
//make the starship appear
[self addChild:_starShip];
//make the paddles
//bottom left one
_Paddle1 = [CCSprite spriteWithFile:#"spritePaddle.jpeg"];
int bottomOfScreenX = 0 + _Paddle1.contentSize.width/2;
int bottomOfScreenY = 0+_Paddle1.contentSize.height/2;
_Paddle1.position = ccp(bottomOfScreenX,bottomOfScreenY);
[self addChild:_Paddle1];
//bottom right one
_paddle2 = [CCSprite spriteWithFile:#"spritePaddle.jpeg"];
int bottomRightOfScreenX = winSize.width - _paddle2.contentSize.width/2;
_paddle2.position = ccp(bottomRightOfScreenX, bottomOfScreenY);
[self addChild:_paddle2];
//make thingsInSpace spawn at a set interval
int setInterval = (arc4random() % 3);
[self schedule:#selector(gameLgoic:) interval:setInterval];
//enable touch
[self setIsTouchEnabled:YES];
}
return self;
}
// 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];
}
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//make the screens and create events
CGSize winSize = [CCDirector sharedDirector].winSize;
NSSet *allTouches = [event allTouches];
UITouch *touch = [allTouches anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
//check to see if the left paddle is being pressed
if (CGRectContainsPoint([_Paddle1 boundingBox], location)){
int bottomLeftOfScreenX = 0 + _Paddle1.contentSize.width/1.25;
//make an action
//the Y-coordinate of starShip must be the same since the ship must move parallel to it.
id action = [CCMoveTo actionWithDuration:2 position:ccp(bottomLeftOfScreenX,1.25*_starShip.contentSize.height) ];
//have starship call this action
[_starShip runAction:action];
[action setTag:1];
}
//check to see if the right paddle is being pressed
if (CGRectContainsPoint([_paddle2 boundingBox], location)){
int bottomRightOfScreenX = winSize.width - _paddle2.contentSize.width/1.25;
//make an action
//the Y-coordinate of starShip must be the same since the ship moves parallel to it
id action2 = [CCMoveTo actionWithDuration:2 position:ccp(bottomRightOfScreenX,1.25*_starShip.contentSize.height) ];
//starShip is now running this specified action
[_starShip runAction:action2];
[action2 setTag:2];
}
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//if the player stops touching the pads, all the aciton should stop.
//left button stop
[_starShip stopActionByTag:1];
//right button stop
[_starShip stopActionByTag:2];
}
#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
spaceThings.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface SpaceThings : CCSprite
#property (nonatomic, assign) int minMoveDirection;
#property (nonatomic, assign) int maxMoveDirection;
-(id)initWithFile:(NSString *)file minMoveDirection:(int)minMoveDirection maxMoveDirection:(int)maxMoveDirection;
#end
#interface Astroids : SpaceThings
#end
#interface SpaceJunk : SpaceThings
#end
SpaceThings.M
#import "SpaceThings.h"
#implementation SpaceThings
-(id)initWithFile:(NSString *)file minMoveDirection:(int)minMoveDirection maxMoveDirection:(int)maxMoveDirection
{
if ((self =[super initWithFile:file])){
self.minMoveDirection = minMoveDirection;
self.maxMoveDirection = maxMoveDirection;
}
return self;
}
#end
#implementation Astroids
-(id)init
{
if (self = [super initWithFile:#"astroid.jpeg" minMoveDirection:2 maxMoveDirection:5]){
}
return self;
}
#end
#implementation SpaceJunk
-(id)init
{
if (self = [super initWithFile:#"blueDot.jpg" minMoveDirection:4 maxMoveDirection:7]){
}
return self;
}
#end
I'm wondering as to where to put CGRectInteresectRect part of the code. As I've currently tried placing within the SpaceJunk alloc init part and it doesn't remove the child when the ship collides with the junk.
int setInterval = (arc4random() % 3);
[self schedule:#selector(gameLgoic:) interval:setInterval];
Make setInterval value to float and give small value for schedular.
Also not do [spaceThings runAction inside loop. if required then do some condition check and run only if required.
Then your CGRectIntersectsRect will fire when intersect each other.
Happy Coding.
To be able to pan and zoom some of the content in screen I decided to use CCLayerPanZoom extension. When I look at the source code I can see that it derives from the CCLayer class. So I change the parent class of the node that's pushed to the navigation stack from CCLayer to CCLayerPanZoom. But what I get when the app launches is just a black screen. To make it cleaner, I created a new class, derived it from CCLayerPanZoom, added a test sprite onto it in the init method and pushed it to the navigation stack in the AppDelegate.m. Still I got nothing, just a black screen. Here're the two methods that I've implemented in my class:
#interface TestPanZoom : CCLayerPanZoom {
}
+(CCScene *) scene;
#end
#implementation TestPanZoom
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
TestPanZoom *layer = [TestPanZoom node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(id)init{
if(self=[super init])
{
CCSprite *sprite=[CCSprite spriteWithFile:#"Default.png"];
sprite.scale=0.5;
[self addChild:sprite];
}
return self;
}
#end
I don't know whats wrong, maybe because i'm using more layers?
I think that my other layer (sliding menu grid subclass is stealing the touches...)
//
// BGLayer.m
// MainProject
//
// Created by NSSL1 on 8/30/12.
// Copyright (c) 2012 MyCompanyName. All rights reserved.
//
#import "BGLayer.h"
#import "GameManager.h"
#import "MainMenuLayer.h"
#interface BGLayer()
-(void)displayBGMenu;
#end
#implementation BGLayer
-(void)backtomenu:(CCMenuItem*)itemPassedIn{
CCLOG(#"why I can't reach here?");
[[GameManager sharedGameManager] runSceneWithID:kMainMenuScene];}
-(id)init {
self = [super init];
if (self != nil) {
self.isTouchEnabled=YES;
[self displayBGMenu];
}
return self;
}
-(void)displayBGMenu{
NSString* backLabelstring = [NSString stringWithFormat:#"Back to Menu"];
CGSize screenSize = [CCDirector sharedDirector].winSize;
//Shadow
CCLabelTTF *backLabel = [CCLabelTTF labelWithString:backLabelstring fontName:#"Marker Felt" fontSize:32];
backLabel.position=CGPointMake(screenSize.height*0.5f, screenSize.width*0.1f);
backLabel.color = ccBLUE;
CCMenuItem* backbtnitem=[CCMenuItemLabel itemWithLabel:backLabel target: self
selector:#selector(backtomenu:)];
[backbtnitem setTag:21];
menu = [CCMenu menuWithItems:backbtnitem ,nil];
menu.position = CGPointMake((screenSize.width / 2), screenSize.height*0.1f);
menu.tag = 200;
[self addChild:menu z:20 tag:200];
}
#end
I had an issue with layers swallowing touches in the same type of class, and to avoid this someone suggested me to add this in the grid button item class init method:
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:-1 swallowsTouches:YES];
The effect is that the class calling this method would not be greedy towards the parent's layer touch detector by detecting only the touches in its area, and would allow the user to scroll the menu in a smooth way as well as pressing other items in the parent layer (such as your menu).
When i call relpaceScene or pushScene in cocos2d, I can add some transitions to it like:
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1 scene:scene]];
but when i call popScene, it takes no parameters, and no transition can be added. Is that so?
How can i popScene with desired transitions?
Per Guy in the cocos2d forums this seems to work: Link to Forum
Add this to CCDirector.h, just after the declaration -(void)popScene (line 402):
- (void) popSceneWithTransition: (Class)c duration:(ccTime)t;
Then add this to CCDirector.m, just after the definition of -(void)popScene (line 768):
-(void) popSceneWithTransition: (Class)transitionClass duration:(ccTime)t;
{
NSAssert( runningScene_ != nil, #"A running Scene is needed");
[scenesStack_ removeLastObject];
NSUInteger c = [scenesStack_ count];
if( c == 0 ) {
[self end];
} else {
CCScene* scene = [transitionClass transitionWithDuration:t scene:[scenesStack_ objectAtIndex:c-1]];
[scenesStack_ replaceObjectAtIndex:c-1 withObject:scene];
nextScene_ = scene;
}
}
You can call the method like this:
[[CCDirector sharedDirector] popSceneWithTransition:[CCSlideInRTransition class] durat
You can use Category as follows:
#interface CCDirector (PopTransition)
- (void)popSceneWithTransition:(Class)transitionClass duration:(ccTime)t;
#end
#implementation CCDirector (PopTransition)
- (void)popSceneWithTransition:(Class)transitionClass duration:(ccTime)t {
[self popScene];
// Make Transition
if (nextScene_) {
CCScene* scene = [transitionClass transitionWithDuration:t scene:nextScene_];
[scenesStack_ replaceObjectAtIndex:([scenesStack_ count] - 1) withObject:scene];
nextScene_ = scene;
}
}
#end
This way you need not to modify CCDirector class.
I modified Kailash's answer to work with cocos2d 2.1.
CCDirector+additions.h
#import "cocos2d.h"
#interface CCDirector (additions)
-(void)popSceneWithTransition:(Class)transitionClass duration:(ccTime)t;
#end
CCDirector+additions.m
#import "CCDirector+additions.h"
#implementation CCDirector (additions)
-(void)popSceneWithTransition:(Class)transitionClass duration:(ccTime)t {
[self popScene];
// Make Transition
if (_nextScene) {
CCScene* scene = [transitionClass transitionWithDuration:t scene:_nextScene];
[_scenesStack replaceObjectAtIndex:([_scenesStack count] - 1) withObject:scene];
_nextScene = scene;
}
}
#end
A more concise version of the above that actually releases the scene so it and its textures can be cleaned up as needed.
CCDirector+addition.h
#import "cocos2d.h"
#interface CCDirector (addition)
- (void) popSceneWithTransition:(Class)transitionClass duration:(ccTime)t;
#end
CCDirector+addition.m
#import "CCDirector+addition.h"
#implementation CCDirector (addition)
- (void) popSceneWithTransition:(Class)transitionClass duration:(ccTime)t {
[_scenesStack removeLastObject];
NSUInteger count = [_scenesStack count];
NSAssert(count > 0, #"Don't popScene when there aren't any!");
CCScene* scene = [transitionClass transitionWithDuration:t scene:[_scenesStack lastObject]];
[self replaceScene:scene];
}
#end
Without having to mess with Cocos2d internals you can do it like:
CCDirector *director = [CCDirector sharedDirector];
CCScene *currentScene = [director runningScene];
CGSize contentSize = [currentScene contentSize];
CCLayerColor *black = [[CCLayerColor alloc] initWithColor:ccc4(0, 0, 0, 0) width:contentSize.width height:contentSize.height];
[currentScene addChild:black];
[black runAction:[CCSequence actionOne:[CCFadeTo actionWithDuration:1.0f opacity:255]
two:[CCCallFunc actionWithTarget:director selector:#selector(popScene)]]];