I'm creating a Cocos2D app that will have between 4 - 12 sprites that the user can interact with/move (Sprites 1 - 4 in the pic). There will be an equal number of target sprites that the user will be able to drag the other sprites to (Targets 1 - 4 in the pic). I was thinking about adding tags to all of the sprites to differentiate between them. What I'm having difficulty with is determining the proper way to keep track of the moveable sprites in relation to what target sprites each of them are on top of.
How should I keep track of these relationships?
Sprite 1 - Target 3
Sprite 2 - Target 1
Sprite 3 - Target 2
Sprite 4 - Target 4
Create two different isntance mutable arrays to hold your objects and an array to hold your correct answers i.e.
//In your .h
NSMutableArray *_targets;
NSMutableArray *_moveableSprites;
NSArray *_answers;
//In your .m
_targets = [[NSMutableArray alloc] init];
_moveableSprites = [[NSMutableArray alloc] init];
_answers = [[NSArray alloc] initWithObjects:#"101", #"103", #"102", #"104", nil];
When you create your sprites assign a tag value to them i.e.
CCSprite *target1 = [CCSprite spriteWithFile:#"file.png"];
//Make sure target tags start from 0 and increment up
target1.tag = 0;
Then before you add each sprite to your layer add them into your respective arrays i.e.
[_targets addObject:target1];
You can then write a method to check sprite position (something similar to this):
- (void)checkSprites {
for(CCSprite *sprite in _moveableSprites) {
for(CCSprite *target in _targets) {
if(CGRectIntersectsRect(sprite.boundingBox, target.boundingBox)) {
if(sprite.tag == [_answers objectAtIndex:target.tag]) {
// Correct sprite in target.....do stuff
} else {
// Not correct sprite.....do stuff
}
}
}
}
}
Related
I have a field full of sprites (30x30).
Before creating any sprite I am preloading my texture atlas with this code:
- (void)preloadAllAtlases
{
BGLog();
_tilesAtlas = [SKTextureAtlas atlasNamed:#"Tiles"];
_tilesTextures = [NSMutableDictionary new];
__weak typeof (shared) weakSelf = self;
[SKTextureAtlas preloadTextureAtlases:#[_tilesAtlas]
withCompletionHandler:^
{
for (NSString *textureFullName in weakSelf.tilesAtlas.textureNames) {
NSString *textureName = [textureFullName componentsSeparatedByString:#"#"][0];
weakSelf.tilesTextures[textureName] = [SKTexture textureWithImageNamed:textureName];
}
}];
}
This method is called from singleton once - in appicationDidFinishLaunchingWithOptions.
When time comes I generate SKSpriteNodes from SKTextures and add compound node (node which contains all SKSpriteNodes) to SKScene. But... it takes from 1 to 1.5 seconds to display/render 192 sprites. With "Time profiler" I have found that [SKSpriteNode spriteNodeWithTexture:] takes waaaaay to much time.
Screenshot:
Is there any way to speed up sprite creation?
Thx.
I want to create a starry sky for some scenes.
The main problem is it needs some time to fill all the screen with particles. Someone advices me to create the whole sky at the beginning and save it between its calls.
I tried something like this:
#implementation StarrySky
static StarrySky *_starrySky;
- (id)init
{
if ((self = [super init])) {
NSArray *starsArray = [NSArray arrayWithObjects:#"Stars1.plist", #"Stars2.plist", #"Stars3.plist", nil];
for(NSString *stars in starsArray) {
CCParticleSystemQuad *starsEffect = [CCParticleSystemQuad particleWithFile:stars];
[self addChild:starsEffect z:-2];
}
}
return self;
}
+ (StarrySky *)sharedStarrySky
{
if (!_starrySky) {
_starrySky = [[StarrySky alloc] init];
}
return _starrySky;
}
- (void)dealloc
{
_starrySky = nil;
[super dealloc];
}
#end
But the particles stop moving.
One solution that ought to work is to create the star particle system and add it to your first scene (ie main menu). Set it to invisible or move it way off the screen or behind the background image (lowest z-order) so it can create some stars without actually showing any stars in the menu.
Now when you switch to your actual game scene, you alloc/init the game scene and then remove the star particle system from the currently running scene and add it to the game scene. Basically you're moving it from one scene to another.
Now you can call replaceScene with the game scene which now contains the already active star particle system.
I have an Array of CCSprites that being displayed all at once.
Every sprite has a movement path, a movement path is a random point on screen.
All the sprites are moving all at once to random points on screen.
What I want to do is to detect collision between the sprites and then change their movement path.
Is it possible?
Iterate through every CCSprite in your array (call it A), and for every iteration iterate again through every CCSprite in the array (excluding A itself of course) (call this one B). Now, use CGRectIntersectsRect along with boundingBox to find a collision between them. It goes something like this:
for (CCSprite *first in mySprites) {
for (CCSprite *second in mySprites) {
if (first != second) {
if (CGRectIntersectsRect([first boundingBox], [second boundingBox])) {
// COLLISION! Do something here.
}
}
}
}
Edit: But of course, it is possible that if two sprites collide, the "collision event" will occur twice (first from the point of view of sprite A, and then from the point of view of sprite B).
If you only want the collision event to trigger once every check, you will need to memorize the pairs so that you can ignore collisions that already did happen on that check.
There are countless ways you could check for that, but here's an example (updated code):
Edited again:
NSMutableArray *pairs = [[NSMutableArray alloc]init];
bool collision;
for (CCSprite *first in mySprites) {
for (CCSprite *second in mySprites) {
if (first != second) {
if (CGRectIntersectsRect([first boundingBox], [second boundingBox])) {
collision = NO;
// A collision has been found.
if ([pairs count] == 0) {
collision = YES;
}else{
for (NSArray *pair in pairs) {
if ([pair containsObject:first] && [pair containsObject:second]) {
// There is already a pair with those two objects! Ignore collision...
}else{
// There are no pairs with those two objects! Add to pairs...
[pairs addObject:[NSArray arrayWithObjects:first,second,nil]];
collision = YES;
}
}
}
if (collision) {
// PUT HERE YOUR COLLISION CODE.
}
}
}
}
}
[pairs release];
Have a look at this S.O. answers.
You can do simple collision detection using CGRectIntersectsRect and the node boundingBox. If you need more advanced features, have a look at a physics engine like chipmunk or Box2D.
Ray Wenderlich has written a good tutorial about using Box2D just for collision detection, if you're interested in going that way. http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone
Check first that your sprites can be approximated by rectangles. If so then #Omega's answer was great. If they can't be, perhaps because they contain a lot of transparency or for some other reason, you might need to approximate your sprites with polys and work with those.
I am building a game for iphone, I am new to game devolopment and somewhat new to the language. I have balls that fall from the top of the screen to the bottom and the player is supposed to try and catch them. The problem is, I add the new sprites with an "addnewBallSprite" method, and later act on the position in my UpdateEveryFrame method. But if there is still a ball on the screen when a new ball is created the old ball stops moving. Is there a way I can make my change in position command control all instances of the ball sprite??? Please explain in detail. Below is my addNewBall method:
-(void) addNewBall {
int RandomXPosition = (arc4random() % 240) + 40;
int RandomBallSprite = (arc4random() % 5);
NSString *BallFileString = #"OrangeBall.png";
switch (arc4random() % 5) {
case 1:
BallFileString = #"OrangeBall.png";
break;
case 2:
BallFileString = #"GreenBall.png";
break;
case 3:
BallFileString = #"YellowBall.png";
break;
case 4:
BallFileString = #"PinkBall.png";
break;
case 0:
BallFileString = #"BlueBall.png";
break;
}
Ball = [CCSprite spriteWithFile:BallFileString];
Ball.position = ccp(RandomXPosition, 520);
[self addChild:Ball z:1];
}
If you want to run some action (i mean CCAction or something other if you want) on the sprite you should have a pointer to this sprite. So you can create an NSMutableArray to keep those pointers and then to interact with them. If the only children of you CCLayer are balls - you can take there pointers via calling children method on your CCLayer.
EDIT
If you have many balls the only way to interact with them is to keep their pointers. Add this declaration to your class:
NSMutableArray *ballArray_;
Initialize array in your class init method:
ballArray_ = [[NSMutableArray alloc] init];
When you create a new ball add the ball to the array:
[ballArray addObject:myNewBall];
And now in your update method you can have the access to each ball in your scene:
for (Ball *ball in ballArray)
{
//increase the position of the ball
}
When the ball is catched by User or out of the scene remove it from array:
[ballArray removeObject: someBall];
I'm making a game with cocos2d and I have a bunch of sprites that I would like to delete. For example I might have a bunch of characters on the screen but when my game is over I would like to clean them up. Right now I have created a special effect (particle system) as a distraction, but because it is transparent and does not cover all of the screen you can see through and watch the sprites disappear as I remove them from the layer.
Also because the instructions execute so fast to the user it appears as if the sprites disappear before the particle effect begins!
Any suggestions on my 2 problems? Thanks.
NSMutableArray *toRemove = [[NSMutableArray alloc] init]; // array of sprites that I collect to remove
spriteCount = 0;
if([self findAllSprites:parent forRemoval:toRemove] > 0){ // is there is at least one sprite to delete. If not then don't do anything
[self specialEffect]; // runs for maybe 3 seconds.
// how can I stall here so that the sprites aren't removed "instantaneously"?
for (Character* aCharacter in toRemove) {
[aCharacter.parent remove:aCharacter];
}
}
You can delay the removal action using performSelector:withObject:afterDelay:. For example:
NSMutableArray *toRemove = [[NSMutableArray alloc] init]; // array of sprites that I collect to remove
spriteCount = 0;
if([self findAllSprites:parent forRemoval:toRemove] > 0){ // is there is at least one sprite to delete. If not then don't do anything
[self specialEffect]; // runs for maybe 3 seconds.
[self performSelector:#selector(removeSprites:) withObject: toRemove afterDelay:1.0];
}
[toRemove release];
- (void) removeSprites: (NSArray*) toRemove
{
for (Character* aCharacter in toRemove) {
[aCharacter.parent remove:aCharacter];
}
}
Note that performSelector:withObject:afterDelay: will retain the toRemove object and keep it alive until after it calls removeSprites, so you don't have to do anything special with toRemove (except that you still need to release it as shown since you own it as well).
You need to do your 'special effect' in a thread, so that it runs alongside your sprite remove. Lookup NSThread for more information, but this will enable you to synchronize the two processes.