how to detect phyisic collision in different class Sprite Kit - ios

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).

Related

Trying to access the Class from GameLayer

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.

How to call a method of super class form subclass SpriteKit

I subclass the SKSpriteNode to create a SKButton in SKButton.h
#interface SKButton : SKSpriteNode
now I want to change the button image by method in SKButton.m
self = [SKSpriteNode spriteNodeWithImageNamed:image];
here self is SKButton but it is giving me error
Cannot assign to 'self' outside of a method in the init family
Incompatible pointer types assigning to 'SKButton *' from 'SKSpriteNode *'
I also tried this in SKButton.m
self = [self spriteNodeWithImageNamed:image];
It gives me error
No visible #interface for 'SKButton' declares the selector
'spriteNodeWithImagedNamed:'
spriteNodeWithImageNamed: is a class method on SKSpriteNode that returns a new SKSpriteNode using the supplied image. Essentially, what you are trying to do with this line -
self = [SKSpriteNode spriteNodeWithImageNamed:image];
is change the current object into a new object - which you can't do. Even if you could, it would be a new SKSpriteNode, not a new SKButton.
What you need to do is manipulate the texture property of your node -
self.texture=[SKTexture textureWithImageNamed:image];
In this line:
self = [SKSpriteNode spriteNodeWithImageNamed:image];
you are downcasting a SKSpriteNode to SKButton which is incorrect as a SKSpriteNode instance does not have the extra implementation provided by SKButton.
Since SKButton is a SKSpriteNode subclass it contains all its functionality so you can just do:
- (void)buttonClicked {
[self setTexture:[SKTexture textureWithImageNamed:"buttonClicked.png"]];
}

Sprite Kit SKActions not firing

I'm working on a project in Objective-C / Sprite Kit and cannot get Sprite Kit actions to work, I have tried everything I have seen but nothing has worked.
Here is some code:
myscene.h
#property (strong, nonatomic) SKAction *jumpAction;
#property (strong, nonatomic) SKAction *kneelAction;
#property (strong, nonatomic) SKAction *runAction;
myscene.m (init w/ size method)
[self setupCharacter];
[self createDpad];
[self spawnStartupClouds];
//self.physicsWorld.gravity = CGVectorMake(0.2,-2);
self.physicsWorld.gravity = CGVectorMake(0.2 ,-2);
self.physicsWorld.contactDelegate = self;
[self setupActions];
myscene.m (setupActions method)
-(void) setupActions{
SKTextureAtlas *jumpAtlas = [SKTextureAtlas atlasNamed:#"jump"];
SKTexture *jumpTex1 = [jumpAtlas textureNamed:#"jump1.png"];
SKTexture *jumpTex2 = [jumpAtlas textureNamed:#"jump2.png"];
SKTexture *jumpTex3 = [jumpAtlas textureNamed:#"jump3.png"];
NSArray *jumpAtlasTexture = #[jumpTex1, jumpTex2, jumpTex3];
SKAction* jumpAtlasAnimation = [SKAction animateWithTextures:jumpAtlasTexture timePerFrame:0.1];
SKAction* wait = [SKAction waitForDuration:0.5];
jumpAction = [SKAction sequence:#[jumpAtlasAnimation, wait]];
BBCharacter* leader = (BBCharacter*)[self childNodeWithName:#"character1"];
}
-(void)setupCharacter{
NSLog(#"Setup character");
leader = [BBCharacter node];
leader.position = CGPointMake(100, 230);
[self addChild:leader];
}
It also seems (in setupActions) it cannot "see" the SKAction jumpAction...
When you declare a property in Objective-C in any class interface, you need to access it in the implementation using self.propertyName. You can also access the instance variable associated with that property by using _propertyName. So, the jumpAction property can be accessed using either self.jumpAction or simply _jumpAction.
This is because the property is not actually an instance variable, but an encapsulation over the class' data. Please have a look at the documentation for a proper explanation.
Alternatively, to be able to access the property using it's exact name, you can explicitly synthesize it in the implementation.
#implementation MyScene //synthesize properties below this.
#synthesize jumpAction, kneelAction, runAction;
After doing so, you can access the properties directly, as you already do in your code.
A suggestion: You do not need to use properties for SKAction objects unless they need to be accessed by other classes.
hope this will help you
ok , By seeing your code i am able to understand that you have number images on your jump.atlas folder
and You want to animate your player to those texture when player jumps off .
so first of all add this line
[_playerNode runAction: jumpAction];
I am not seeing this line in your code.
You have all the actions set up, now you just need to tell the node to perform the action with the runAction method. If you are running the action then be most specific when you say you cannot get the actions to work.

Calling my enemy class method from the game scene

I'm still fairly new to programming and what I tried to do is the following: So I separated my Enemies from my game scene to a different class. In the Enemy class.m file I declared 6 methods. Every method represents a new level, which will get called from the game scene. So in the methods I declare the sprite's image, path, shooting particle type, etc.. Here's an example of the level 1 method in the EnemyClass.m file:
#implementation EnemyClass
+(void)enemiesLevel1
{
EnemyName = #"enemy1";
SKSpriteNode* enemy = [SKSpriteNode spriteNodeWithImageNamed:EnemyName];
pathSpeed = 3;
CGPathRef path = CGPathCreateWithEllipseInRect(CGRectMake(0,0,400,400), NULL);
SKAction *followTrack = [SKAction followPath:path
asOffset:NO
orientToPath:YES
duration:pathSpeed];
SKAction *forever = [SKAction repeatActionForever:followTrack];
SKAction *addEnemy = [SKAction runBlock:^{
[self addChild: enemy];
}];
SKAction *enemySequence = [SKAction sequence:#[addEnemy, forever]];
[self runAction: enemySequence];
}
However, Xcode is states two issues:
No known class method for selector "addChild"
and
No known class method for selector "runAction"
I'm calling the method from GameScene.m with:
[EnemyClass enemiesLevel1]
Here's EnemyClass.h if anyone's wondering:
#interface EnemyClass : NSObject
+(void)enemiesLevel1;
+(void)enemiesLevel2;
+(void)enemiesLevel3;
+(void)enemiesLevel4;
+(void)enemiesLevel5;
+(void)enemiesLevel6;
#end
It may seem like a dumb question, but I am still new and I would greatly appreciate any help!
BTW: I did import the sprite kit framework.
Your EnemyClass doesn't have addChild or runAction methods, as it doesn't inherit from SKNode or a subclass of SKNode.
change :
#interface EnemyClass : NSObject
to
#interface EnemyClass : SKNode
Update :
Also, you have enemiesLevel1 etc defined as class methods. They need to be instance methods if you intend to sue addChild with them.
Here's a question that might help you :
What is the difference between class and instance methods?
Be sure to read all the answers, as a few of them have good info you should be aware of.
Change
+(void)enemiesLevel1
{
....
}
To
-(void)enemiesLevel1
{
....
}
The + in front of a method means it is a class method, and the - means it is an instance method. An instance method can not be called from a class method. Please read the link prototypical provided for you so you can better understand the differences between them.

Implementing CCSprite class into my game

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];

Resources