In my game, I use Cocos2D for physics in the gameplay and UIKit for the menu screen and the rest of the game. Now, I have to pass the data from a UIViewController to a Cocos2D scene. Is there a way to do this?
I think you can do it by assigning value to a class variable....
Code snippet will look like this...
[[CCDirector sharedDirector] replaceScene:[GameScene scene:data]];
in your GameScene.m
#implementation GameScene
#synthesize ...
+ (CCScene *) scene:(Datatype *)data
{
self.dataReceived = data;
CCScene * .....
.......
}
Something like this may help.. I did this in cocos2d-x and it works fine.. M sorry for syntax as I don't have X-code.... :)
Related
I have a class called Blade.h and I make A SKSpriteNode on that!
now I make new instance of that class on Main Class.
#import "Blade.h"
#implementation Blade
-(void) GenerateBalde
{
SKSpriteNode *blade = [SKSpriteNode spriteNodeWithImageNamed:#"blade"];
[blade runAction:[SKAction rotateByAngle:M_PI duration:1]];
[self addChild:blade];
}
#end
now, I want to have an instance of this object in my main class and I wanna detect the physic collision the Blade with another Sprites in my main class!
I know how to make an instance , but I wanna know how to detect the collision of different objects in different classes + physic!
please advice!
It would be better if your Blade was a subclass of SKSpriteNode and then in its init method use:
if (self = [super initWithImageNamed:#"blade"]){
//more code
}
return self;
Another solution is to use a property, so instead of creating a SKSpriteNode in generateBlade method use this:
In Blade.h add #property (nonatomic, retain) SKSpriteNode *bladeSprite.
In your generateBlade method, use this:
self.bladeSprite = [SKSpriteNode spriteNodeWithImageNamed:#"blade"];
[self.bladeSprite runAction:[SKAction rotateByAngle:M_PI duration:1]];
[self addChild:self.bladeSprite];
Then, in your MainScene, in update: method, you can check the collision using this code:
-(void)update:(CFTimeInterval)currentTime {
if (CGRectIntersectsRect(otherObject.frame, blade.bladeSprite.frame){
//Collisioning!
}
}
If you are using a SKSpriteNode subclass as mentioned in first lines, you could just do blade.frame instead of blade.bladeSprite.frame (you won't need to set a property).
I'm working on a game with a primary player as an SKSpriteNode. The game has a concept of powerups that can be acquired, and each player can have a set of attachments.
I have a protocol for attachments defined as:
#protocol ESPlayerAttachment <NSObject>
#required
-(ESPlayerAttachmentType)attachmentType;
#optional
-(void)willAttachToPlayer:(ESPlayerSpriteNode *)player;
-(void)didDetachFromPlayer:(ESPlayerSpriteNode *)player;
-(void)player:(ESPlayerSpriteNode *)player willUseAttachmentInParent:(SKNode *)parent;
#end
Additionally, I have a protocl for powerups defined as:
#protocol ESPlayerPowerup <NSObject>
-(void)acquiredByPlayer:(ESPlayerSpriteNode *)player;
#end
Finally, I have a physics body on the power up box, as well as one on the player so that I can detect the collision and attach the powerup. As an example, I have a shield powerup that is implemented as:
-(void)willAttachToPlayer:(ESPlayerSpriteNode *)player
{
[player detachAttachmentsOfType:ESPlayerAttachmentTypeShield];
__weak ESPlayerShipSpriteNode *weakPlayer = player;
[player.parent addChild:_shield];
_shield.position = CGPointMake(player.position.x, player.position.y + 0.1f * _shield.size.height);
[self performSelector:#selector(detachFromPlayer:) withObject:weakPlayer afterDelay:15.0f];
}
What's bothering me is that if I attach the shield powerup to the player in my SKScene class (in the update or didMoveToView methods), everything works. The shield is positioned correctly. However, if I add it through the ESPlayerPowerup method (which gets called during a collision with the player), the node gets positioned relative to SKScene, so it ends up in the bottom left corner of the screen. I can't seem to figure out what the difference is (there's only one instance of ESPlayerSpriteNode in the game, so I'm relatively confident that isn't the problem)
For what it's worth, I ended up finding this post on SO, which has solved my problem:
SKSPriteNode position changes to 0,0 for no reason
It would seem to be a bug in SpriteKit, but positioning the item before attaching the physicsBody does work, and positions it correctly.
I'm trying to learn Cocos2D from Learning Cocos2D, A hands-on guide by Rod Strougo & Ray Wenderlich, but it uses Cocos 1, not 2 which is out now. I imagine the book is still relevant later on, but in the first chapter I'm running into an issue telling the director to run a scene, because it seems like that whole process is now different in Cocos2D 2.
I'd rather not have to buy a different book, so I was hoping that changing the way to run a scene is fairly simple.
This is what the book says to do:
find the -applicationDidFinishLaunching method and comment out:
[[CCDirector sharedDirector]runWithScene: [HelloWorld scene]];
and add:
[[CCDirector sharedDirector]runWithScene:[GameScene node]];
I can't find anything that looks like that in AppDelegate, instead it looks like this has something to do with the new way:
[director_ pushScene: [IntroLayer scene]];
My attempts to adapt what the tutorial says to the new way has so far failed, but maybe it is an easy fix.
Incase it is the GameScene which is outdated:
GameScene.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "BackgroundLayer.h"
#import "GameplayLayer.h"
#import "CCScene.h"
#interface GameScene : CCScene
{
}
#end
GameScene.m
#implementation GameScene
-(id)init
{
self = [super init];
if (self != nil)
{
BackgroundLayer *backgroundLayer = [BackgroundLayer node];
[self addChild:backgroundLayer z:0];
GameplayLayer *gameplayLayer = [GameplayLayer node];
[self addChild:gameplayLayer z:5];
}
return self;
}
#end
The issue you are having is with the class method +scene. That is used when creating the scene within a layer instead of initializing a scene and having that instance create its own child layers. You will understand the differences later in the book when you get more into the scene -> layer relationship.
Comment out [director_ pushScene: [IntroLayer scene]]; in -applicationDidFinishLaunching and replace it with the following:
[director_ pushScene:[GameScene node]];
That should work just fine for your needs. It will create an instance of GameScene (subclass of CCScene) with your two CCLayer subclass instances as children, those being the backgroundLayer and gameplayLayer you instantiate in the GameScene -init method.
If you are curious as to why calling [GameScene scene] was not working for you, that is because you never declared such a method in your interface. It is a little confusing, but basically you would instead create a Game Layer subclass of CCLayer and in your .h file, declare this class method:
+ (CCScene *)scene;
In your implementation .m file, you would define that method as such:
// Class initializer method
+ (CCScene *)scene {
CCScene *scene = [CCScene node]; // Create a container scene instance
GameLayer *gameLayer = [GameLayer node]; // Create an instance of the current layer class
[scene addChild:gameLayer]; // Add new layer to container scene
return scene; // Return ready-made scene and layer in one
}
Then when you call [GameLayer scene] that +scene method creates the scene for that layer and adds it as a child. It is quicker, but can be more troublesome with multiple layers in my experience.
Have you tried this:
[[CCDirector sharedDirector] pushScene:[IntroLayer scene]];
With Cocos2d v2.0.0, a lot of changes were made and a lot of people are experiencing some scaling problems and other conflicts ...
This is even more true if they read and test out Ray Wenderlich's great book : Learning Cocos2d : The viking guy is to big, the background is not centered, the suffix system for images is not working, ...
So, how to proceed ?
Basically, everything is already told in the sample project when creating a new cocos2d v2 project.
But, some of us need to get things pointed out.
Image Suffix System for iPhone (Non-retina & Retina) and iPad (Non-retina & Retina)
Check out lines 68-71 from AppDelegate.m
Here is what you need to remember :
You just need to call
CCSprite *mySprite = [CCSprite spriteWithFile:#"mySprite.png"];
No need for some if(iPad) then else if(iPhone) blabla
Make sure you called your images like as lines 68-71 from AppDelegate.m (Default : mySprite.png (iPhone) | mySprite-hd.png (iPhone Retina) | mySprite-ipad.png (iPad) | mySprite-ipadhd.png (iPad Retina)
Calling a Scene
Check out line 76 from AppDelegate.m
Just call the scene function from your class (using pushScene)
[director_ pushScene: [MyScene scene]];
Adding layers to your scene class
Supposing your scene class is called with the +(CCSene*)scene function (which is a good practice for cocos2d v2)
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
BackgroundLayer *backgroundLayer = [BackgroundLayer node];
[scene addChild:backgroundLayer z:0];
GameplayLayer *gameplayLayer = [GameplayLayer node];
[scene addChild:gameplayLayer z:5];
return scene;
}
Replacing the init function from your classes (CCScene, CCLayer, ...)
This is where scaling problems from v2 of cocos2d come from (but I do not know why).
Instead of calling -(id)init, call
-(void) onEnter{ //Do some sprite displaying with [self addChild:mySprite]; }
You can still call the -(id)init function for other things you need to load before displaying sprites.
Using SneakyInput (Joystick opensource library)
You can find how to use sneakyinput with cocos2d v2 here : http://cl.ly/1J2D2z0f3o0r3h041o3o
Multi Touch Enabling
Add this line to your layer (in the +(CCScene*) scene function or else where)
layer.isTouchEnabled = YES;
Then add this to the same .m
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray *touchArray=[touches allObjects];
if ([touchArray count] == 2)
{
NSLog(#"2");
}
else if([touchArray count]==1)
{
NSLog(#"1");
}
}
Finally, go to the AppDelegate.m and add this :
[[CCDirector sharedDirector].view setMultipleTouchEnabled:YES];
I would much appreciate if cocos2d v2 developers could help out and post stuff about how to use cocos2d v2 compared to v1.
cocos2d v2.0 migration guide:
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:migrate_to_v2.0
In my game, which is using cocos2d, there is going to be many different types of enemies, which all look different, and move all in different ways. Also, there is going to be a couple of different gamemodes, which both use the same enemies. As there will be different gamemodes, I decided to make each of my enemies have their own CCSprite class. In those there will be the way that the sprites move, the animation, etc. When one of these sprite is needed in my game, they will be spawned in to the scene. The only thing is, how do I do this? How do I call for one of the sprites to be create on the screen when they are using a class of their own?
If you want to tell me another way than having these sprites having their own classes, that is fine, but keep in mind that I will be having a couple of different gamemodes. If I do the code for the sprites in the CCLayer class of that gamemode, well I will have to write the code twice, which will take time.
Thanks.
You can just subclass CCSprite and override the default initializer initWithTexture:rect:
example taken from here
#implementation MySprite
-(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect
{
if( (self=[super initWithTexture:texture rect:rect]))
{
// initialize your ivars here
//ivar1 = xxx;
//ivar2 = yyy;
//ivar3 = zzz;
}
return self;
}
#end
// And to create an instance of MySprite you simply do:
MySprite *sprite = [MySprite spriteWithFile...];
// or any of the supported CCSprite methods.
you can have a super class say EnemySprite that looks like this
#interface EnemySprite : CCSprite
- (void)addToLayer:(CCLayer *)layer;
- (void)removeFromLayer:(CCLayer *)layer;
#end
than create a subclass for each type of enemy for example:
#inteface BigEnemySprite : EnemySprite
#end
#implementation BigEnemySprite
- (void)addToLayer:(CCLayer *)layer {
[layer addChild:self];
// animation code for your big enemy
}
- (void)removeFromLayer:(CCLayer *)layer {
[layer removeChild:self];
// animation code
}
#end
than you can use them like
EnemySprite *enemy = [BigEnemySprite spriteFromFile:file];
[enemy addToLayer:self];