I have a "bomb" CCSprite in its own class(If people who doesn't use cocos2d reads this, CCSprite is a NSObject pretty much).
The CCSprite file looks like this:
Bomb.h:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import <OpenAL/al.h>
#class HelloWorldLayer;
#interface Bomb : CCSprite {
#private
int length;
}
#property (readwrite) int length;
#end
Bomb.m:
#import "Bomb.h"
#implementation Bomb
#synthesize length = _length;
#end
I add it in my game layer (HelloWorldLayerlike a pro) with #class Bomb; in .h, and I import the Bomb.h in my HWLayer.m aswell and where I use it in my code, is here:
Bomb *bombe = [[Bomb alloc] init];
bombe.position = explosionPoint;
bombe.length = player.explosionLength; //player is another CCSprite class. This one is from the method. ....fromPlayer:(PlayerSprite *)player
//Logging here works, tested and the bombe.position is valid and .length is valid
[currentBombs addObject:bombe];
NSLog(#"%#",currentBombs); //Here doesn't, guessing crash is at ^
As said, it crashes on the addObject:line. I can't really see why, as I just replaced a not-classed CCSprite with a Bombclass.
The crash is just a (lldb) and the thing on the left outputs a few thousand of these:
Which says description, so I would assume its in my CCSprite subclass the error is. BUT the bombe.* logging worked fine!
Does anyone understand why it doesn't work?
Edit:
EDIT:
NSLog(#"%#",currentBombs); //Here doesn't, guessing crash is at ^
Your %# implies NSString. currentBombs is likely an int. Try
NSLog(#"%i",currentBombs); //Here doesn't, guessing crash is at ^
CCSprite requires a texture. You can (maybe?) have a CCSprite without one, but that's not what CCSprite is for.
You will want to use CCNode for this purpose:
CCNode* node = [CCNode new];
This is a full-fledged Cocos2d object that you can move, etc. You'd add your Bomb to it, and move the CCNode around, like this:
Bomb *myBomb = [Bomb new]; //or whatever
CCNode* bombNode = [CCNode new];
//add the bomb to the node
[bombNode addChild:myBomb];
//move the node
bombNode.position = CGPointMake(10, 20)
This allows you to remove the myBomb from your node, effectively having something that you can add whatever you want without needing to display anything, but when you want to, it can be done easily.
Good luck
try this method :
Bomb *bombe = [Bomb spriteWithFile:#"yourFile.png"];
bombe.position = explosionPoint;
bombe.length = player.explosionLength;
[currentBombs addObject:bombe];
NSLog(#"%#",currentBombs);
Related
I have a custom class "LinkWithNumber" with three sprites
and on the GameLayer in update I am trying to test
CGRectContainsRect for collisions but I am having trouble trying to access the sprite in the class file (I don't have much experience so most likely I am messing up :P)
I have tried the following:
LinkWithNumber.h
#interface LinkWithNumber : SKSpriteNode <SKPhysicsContactDelegate>
{
SKSpriteNode *collide;
}
LinkWithNumber.m
#synthesize collide;
//add collision object to the class
collide = [[SKSpriteNode alloc]initWithColor:[SKColor blueColor]
...blah blah as normal
[self addChild:collide];
collide.name = #"collide";
GameLayer.h
#class LinkWithNumber;
#interface GameScene : SKScene <SKPhysicsContactDelegate>
{
LinkWithNumber* twoSpritesWithParticlesBridge;
}
#property (nonatomic, strong)LinkWithNumber* twoSpritesWithParticlesBridge;
GameLayer.m
#synthesize twoSpritesWithParticlesBridge;
-(void)addStaticLinkedSpriteWithParticles
{
twoSpritesWithParticlesBridge =
[[LinkWithNumber alloc]initWithlinkSpriteA:#"RoseMine06"
spriteB:#"RoseMine06"
andPlistAnimation:#"need to create animations"
distbetween:300
hasParticles:YES
ParticlesNamed:#"Fire"];
[self addChild:self->twoSpritesWithParticlesBridge];
twoSpritesWithParticlesBridge.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: twoSpritesWithParticlesBridge.frame.size];
}
-(void)update:(CFTimeInterval)currentTime {
LinkWithNumber *currentSprite =
(LinkWithNumber*)[self childNodeWithName:#"collide"];
//NSLog(#"currentSprite Name #%#", currentSprite); //gets nil
if (CGRectContainsRect(myShip02.frame,currentSprite.frame)) {
NSLog(#"Hit barrier can pass");
}
}
Any help would be appreciated :)
How to locate your class object... The Solution, with thanks to 0x141E!
//name it on setup inside your customCLass
//eg yourObject.name = #"collide";
//Now in Gamelayer locate your object by recursive search
//it will look for any object named #"//collide"
//without the slashes it will only look on the game layer
//but since we need to dig a bit further we need them!
LinkWithNumber *currentSprite =
(LinkWithNumber*)[self childNodeWithName:#"//collide"];
NSLog(#"LinkWithNumber is %#",NSStringFromClass([currentSprite class]));
//do something with your object
if (currentSprite.position.y >0 ) {
NSLog(#"currentSprite Position %f",currentSprite.position.y);
}
extras
Sknode Class ref for other search functions
How to enumerate all nodes
I see two issues...
You are searching only the root node (in this case the scene) for the node named "collide", but that node is a child of LinkWithNumber node not the scene. To recursively search the entire node tree, use #"//collide"
You are casting the result of the search to a LinkWithNumber pointer, but collide is an SKSpriteNode not a LinkWithNumber.
I am using sprite builder and Xcode.
Does anyone see where I am going wrong with my code block "whereToNext" property? Im trying to use it to navigate between scenes but for some reason it isn't going into the initialization code in -(void)patterns even though it is going into the patterns method. Since it never goes into the whereToNext=^{} code, when i call it in the next() method nothing happens. (The next method is called via a code connection to a button in sprite builder.)
As a second question concerning CCTextField:
I placed two CCTextField node in my TrialCustomization.cbb (which has the ExperimentSelection custom class code connection) on sprite builder and then created two doc root var code connection "_blocks" and "_trials" then created a variable in the corresponding class with the same name CCTextField *_blocks; and the same for _trials but when i give that text field input it doesn't save it into the variables i saved them into in their corresponding methods.
#import "CCNode.h"
#interface ExperimentSelection : CCNode
#property (nonatomic, copy) void(^whereToNext)(void);
#property CCTextField* _trials;
#property CCTextField* _blocks;
extern int trials;
extern int blocks;
-(void)patterns;
-(void)setTrialandBlock;
#end
#implementation ExperimentSelection
#synthesize whereToNext;
#synthesize _blocks;
#synthesize _trials;
-(void)patterns{
whereToNext=^{
CCScene *patternsSelection = [CCBReader loadAsScene:#"PatternsSelection"];
[[CCDirector sharedDirector] replaceScene:patternsSelection];
NSLog(#"Why is this code not being executed??");
};
NSLog(#"whereToNext: %#", whereToNext);
[self setTrialandBlock];
}
-(void)_trials:(CCTextField*)trialsNum{
trials=[trialsNum.string intValue];
}
-(void)_blocks:(CCTextField*)blocksNum{
blocks=[blocksNum.string intValue];
}
-(void)setTrialandBlock{
CCScene *customizeExperiment = [CCBReader loadAsScene:#"TrialCustomization"];
[[CCDirector sharedDirector] replaceScene:customizeExperiment];
NSLog(#"blocks: %i, trials: %i",blocks, trials);
}
-(void)next{
NSLog(#"wherearewegoingnext: %#, blocks: %i, trials: %i",whereToNext, blocks, trials);
whereToNext();
}
#end
Are you sure what -(void)patterns was called?
If YES, try change
void(^whereToNext)(void);
to
#property(nonatomic, copy) void(^whereToNext)(void);
UPD
I think there is no problem with creation of block or with execution of the block. I think there is some logic problem in the code. May be exist some parent or child class that overload "patterns" method. You can add a break point to property whereToNext and view then this property is changed.
Using apple spritekit, how can I uniquely identify nodes if, say 20 nodes, they have same art work and are to be placed randomly on the screen? Is there a faster way like in cocos2d there is a"tag" function to identify?
I'm not the most proficient with sprites, but is this something you're looking for?
Save:
NSArray * nodesArray; // some array of nodes.
for (int x = 0; x < nodesArray.count; x++) {
SKNode * node = nodesArray[x];
node.name = [NSString stringWithFormat:#"%i", x];
}
Retrieve:
int nodeToRetrieveTag = 2; // or whatever
SKNode* nodeToRetrieve = [self.scene childNodeWithName:[NSString stringWithFormat:#"%i", nodeToRetrieveTag]];
I'm usually using the property name:
SKNode *myNode = [[SKNode alloc]init];
myNode.name = #"uniqueName";
[self addChild:myNode];
In the SKScene, to recovery the node you can do:
[self childNodeWithName:#"uniqueName"]; // self is SKScene
If for some reason you don't want to use name, you can always subclass one SKNode and add your personal unique identifier:
MySpriteNode.h
#interface MySpriteNode : SKSpriteNode
#property (nonatomic, strong) NSString *personalIdentifier;
#end
and
MySpriteNode.m
#import "MySpriteNode.h"
#implementation MySpriteNode
#end
with this second option you can:
for (MySpriteNode *sprite in [self children]) personalIdentifier
{
if ([sprite.personalIdentifier isEqualToString:#"something"])
{
//do something
}
}
EDIT 1:
Try to follow these tutorials, I really think they are great. I learned a lot with them:
An iOS 7 Sprite Kit Game Tutorial
Sprite Kit Programming Guide
Sprite Kit Tutorial for Beginners
Are you looking for enumerateChildNodesWithName:usingBlock: method?
I've implemented 3 classes.
-Scene.m & .h
Scene.m: (has HudLayer & BackgroundLayer properties on the header file)
-(id)init{
self = [super init];
if(self != nil){
//Level1Layer
_level1GameplayLayer = [Level1Layer node];
[self addChild:_level1GameplayLayer z:0];
//Hud Layer
_hudLayer = [HUDLayer node];
[self addChild:_hudLayer z:1];
}
return self;
}
-Which holds these 2 layers
BackgroundLayer.m & .h && HUDLayer.m & .h
Everytime I click the screen I get a Log notice like this "Touched Screen"(called on backgroundlayer.m) which is followed by a function which is implemented on HUDLayer.m & .h
I call it like this:
[_hud getAmmo:self.ammoLeft magsLeft:self.magsLeft];
_hud is stated on the Scene.m like this:(and its imported on backgroundlayer.m)
HUDLayer *hudLayer = [HUDLayer node];
[self addChild:hudLayer z:1];
background is z:0.
Also BackgroundLayer.m has the property under #interface:
(I realized this is nil because its not initialized, How do I initialize this???)
#property (strong) HUDLayer *hud;
Between the call of getAmmo: I make 3 CLOGS, one BEFORE "We're about to getAmmo:"
one INSIDE the function on HUDLayer.m that calls "Inside getAmmo:"
and one AFTER "We gotTheAmmo:"
BackgroundLayer.m:
CCLOG(#"We're about to getAmmo");
_hud getAmmo:self.ammoLeft magsLeft:self.magsLeft];
CCLOG(#"We got the ammo:%d, mags:%d",self.ammoLeft,self.magsLeft);
HUDLayer.m:
-(void)getAmmo:(int)ammo magsLeft:(int)magsLeft
{
CCLOG(#"We did this");
hudMagsLeft=magsLeft;
hudAmmoLeft = ammo;
CCLOG(#"HUD MAGS: %d, AMMO:%d", hudMagsLeft,hudAmmoLeft);
}
Im only getting the one before and the one after, there's no warnings on the way the function is being called but for some reason it isn't being called. There's no if statements or anything..what is it Im doing wrong???
So to make the question more simple, how do I access properties/functions from other classes?
Thank you for your time, have a good one.
On the scene.h I added this function:
-(id)initWithHUD:(HUDLayer *)hud;
Then on the scene.m I made this:
_backgroundLayer = [[[BackgroundLayer alloc] initWithHUD:_hudLayer] autorelease];
on Backgroundlayer.m I changed regular init with
-(id)initWithHUD:(HUDLayer *)hud{
:D
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];