I asked a question recently that sort of involved implementing power-ups; however, I have decided that I want to go about it a different way.
In my game, I have an endless scrolling background and the main character moving to the right while collecting coins.
When the player hits the blue coin, the power-up, I want 1. the character to change to a blue color (I have the frames for this), 2. the background to go blue, and 3. the platform to change blue (have images for this); I would like all these factors to take place for a 20 second period of time.
I planned to do this by having a Blue class with a blue instance variable (public variable) that I would set to YES and NO accordingly (if a blue coin has been hit) in my other classes (Platform class, Player class). However, it is not efficient and does not work for when I incorporate a timer.
Does anyone have an idea on how to implement the power-up?
This is my code for when the blue coin is hit by the player:
// try remove blue coin
- (void) tryRemoveBluecoin
{
NSMutableArray * currentBluecoinArray = [self getcurrentBluecoinArr];
if(currentBluecoinArray)
{
int playerY = ((CCLayer*)(self.player)).position.y;
for(int x=0; x<[currentBluecoinArray count];x++)
{
CCSprite *bluecoin = [currentBluecoinArray objectAtIndex:x];
if(abs(bluecoin.position.x+bluecoin.parent.position.x-[Player initX])<50)
{
if(abs(bluecoin.position.y+bluecoin.parent.position.y-playerY)<30 && bluecoin.visible && bluecoin.visible)
{
[bluecoin.parent removeChild:bluecoin cleanup:YES];
CGSize winSize = [[CCDirector sharedDirector] winSize];
[[SimpleAudioEngine sharedEngine] playEffect:#"jump.wav" pitch:1 pan:0 gain:1];
// SET BLUE VARIABLE TO YES
NSLog(#"BEGIN BLUE POWER UP EFFECTS FOR 20 SECONDS");
}
}
}
}
[self hitTestOB];
}
Thanks for any ideas you have!
Now, it has been some time since I last used Cocos2d, but you are aware that you can actually set color-information to nodes, right? This sounds like a much more sensible way to go down. Design your sprites with this in mind and keep an array with all elements you need to color.
Have a method defining the new color based on your game state, the game state enums can be matched with an NSInteger property on your power-ups for instance.
ccColor3B color;
// _state being an NSInteger ivar
// the different states defined in an enum
switch (_state) {
case gameStateBlue:
color = ccc3(0, 0, 255);
break;
case gameStateGreen:
color = ccc3(0, 255, 0);
break;
default:
break;
// etc.
}
send this color information to a method which handles your array of sprites like this:
for (CCSprite *sprite in _arrayOfSpritesToChangeColor) {
sprite.color = color;
}
This will demand planning ahead with your assets, but a lot more flexibility down the line if you want to experiment with different colors and effects. It is a lot less taxing as well as you won't need to swap a bunch of assets to achieve what you want. Now, my Cocos is rather rusty so I might have messed some details up, but the general idea should be sound.
Edit: An alternative to holding reference to the sprites in an array is to have your own sprite subclass and let that subclass have a CCSprite colorSprite property. Then you could loop through the children of your scene and change the sprites that have this property.
Related
I have a game that uses the camera view, and has enemies flying around the screen. You then shoot the enemies using your chosen weapon. At the moment I have 4 UIImageView's, in which the enemies are animated. I am wanting to have multiple instances of each enemy (there are 4) on the screen, and with time more spawn. What is the best way to do this?
This is part of the code to move one enemy using the gyro: (enemyCyborg is the UIImageView)
valueX4 = gyroData.rotationRate.y* 30;
valueY4 = gyroData.rotationRate.x* 40;
int newX4 = (int)(enemyCyborg.center.x +valueY4);
int newY4 = (int)(enemyCyborg.center.y -valueX4);
CGPoint newCenter4 = CGPointMake(newX4, newY4);
enemyCyborg.center = newCenter4;
And they are moving randomly within that:
- (void) moveCyborg {
[UIView animateWithDuration:1.0f animations:^{
int fromNumber = -30;
int toNumber = 60;
int randomNumber = (arc4random()%(toNumber-fromNumber))+fromNumber;
//Move the image view to 100, 100 over 10 seconds.
enemyCyborg.frame = CGRectMake((int)(enemyCyborg.center.x -randomNumber), (int)(enemyCyborg.center.y -randomNumber), enemyCyborg.frame.size.width, enemyCyborg.frame.size.height);
}];
}
This shows the UIImageView again, after it has been hidden from shooting it:
- (void) showCyborg {
enemyCyborg.hidden = NO;
enemyCyborg.center = CGPointMake((arc4random()%SCREEN_HEIGHT),(arc4random()%SCREEN_WIDTH));
enemyCyborg.animationImages = cyborganim;
enemyCyborg.animationDuration = 0.6;
enemyCyborg.animationRepeatCount = 0;
[enemyCyborg startAnimating];
}
You'll want to create objects encapsulating the enemy model and spawn those objects using some kind of enemy generator function. This generator function might be a written as a class function.
Here are some general suggestions:
1) You're using the block-based animation methods. Blocks are a good approach but depending on your performance and the number of enemies and other visual elements you plan to add, you may want to look into using Cocos2d which gives you all sorts of features. Ray Wenderlich has published a great intro to cocos2d tutorial that would get you up and running quickly. Link to that here. Many games for iPhone are written using either cocos2d or Unity.
2) Check in https://gamedev.stackexchange.com/ for further basic examples, if you haven't done so already.
I'm relatively new to iphone programming, and I've been starting out with cocos2d. I was wondering if there was a way to set opacity for multiple sprites at once? I noticed that opacity isn't implemented for CCLayer, and opacity doesn't seem to propagate down to children of class CCSprite.
Is there any better way to do this than to override setOpacity on a custom ccnode and iterate through and set opacities individually? Or perhaps overriding draw and setting the blending mode manually?
Thanks!
You can loop through all the sprites in your scene, check if they are the sprites you want, then set their opacity like this (assuming you set their tag to OPACITY_SPRITE_TAG when you create the sprites)
for(CCSprite* sprite in [self children])
{
if([sprite tag] == OPACITY_SPRITE_TAG)
{
[sprite setOpacity:NEW_OPACITY];
}
}
Couldn't you just increment through an array of sprites that you want to change. Something like:
for(int i = 0; i < [myArray count]; i++){
CCSprite *mySprite = [myArray objectAtIndex:i];
[mySprite setOpacity:100];
}
I have an iOS game, and when a ball hits a target it explodes.
What would be the best way to animate this explosion?
If you're looking for something simple.
Make a series of images that animate the explosion. Add those to a UIImageView and start the animation. Something like this:
UIImage *image0 = [UIImage imageNamed:#"explosion0.png"];
UIImage *image1 = [UIImage imageNamed:#"explosion1.png"];
UIImage *image2 = [UIImage imageNamed:#"explosion2.png"];
UIImage *image3 = [UIImage imageNamed:#"explosion3.png"];
myImageView.animationImages = [NSArray arrayWithObjects:image0, image1, image2, image3, nil];
[myImageView setAnimationDuration:0.75f];
[myImageView startAnimation];
For a bouncing ball game, the Cocos2D game- and Box2d physics- (included with Cocos2D) engines are a great way to go.
Ray Wenderlich has three great tutorials on exactly what you want to do:
Intro to Box2D with Cocos2D Tutorial: Bouncing Balls
How To Create A Breakout Game with Box2D and Cocos2D Tutorial: Part 1
How To Create A Breakout Game with Box2D and Cocos2D Tutorial: Part 2
Once you get past the basics of working with Box2d objects, the key step is to create a Contact Listener (as described in the tutorials) which will tell you when you have a collision. Check (by iterating over contacts in your tick method) if the colliding objects are the ones you want for the explosion, and if so add them to a vector of objects to be destroyed (we can't do this while iterating over contacts or we will invalidate the iterator). Remember the coordinates of the collision and set a flag for explosion.
After exiting the loop destroy the bodies and run the explosion effect at the saved position.
Cocos2D has some very nice built-in explosion effects, and the one I am using for my project is CCParticleSun. You can find some screenshots of someone using this effect here. (The curiously named CCParticleExplosion just gave a lot of confetti flying around the screen.)
Here is the relevant portion from some preliminary code I have working, which is mostly from the tutorial. You will still need to do everything else, eg. create and set up your world and bodies in your init method, update positions, apply forces, and draw in your tick method, implement your Contact Listener class, etc. For all this refer to the tutorials.
std::vector<b2Body *>toDestroy;
std::vector<MyContact>::iterator pos;
CGPoint p;
bool explode = FALSE;
for(pos = _contactListener->_contacts.begin();
pos != _contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
if ((contact.fixtureA->GetBody() == _moonBody && contact.fixtureB->GetBody() == _moon2Body) ||
(contact.fixtureA->GetBody() == _moon2Body && contact.fixtureB->GetBody() == _moonBody)) {
NSLog(#"Moons collided!");
explode = TRUE;
p = CGPointMake(PTM_RATIO*(_moonBody->GetPosition().x + _moon2Body->GetPosition().x)/2.,PTM_RATIO*(_moonBody->GetPosition().y + _moon2Body->GetPosition().y)/2.);
if (std::find(toDestroy.begin(), toDestroy.end(), _moonBody) == toDestroy.end()) {
toDestroy.push_back(_moonBody);
}
if (std::find(toDestroy.begin(), toDestroy.end(), _moon2Body) == toDestroy.end()) {
toDestroy.push_back(_moon2Body);
}
}
}
std::vector<b2Body *>::iterator pos2;
for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
b2Body *body = *pos2;
if (body->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *) body->GetUserData();
[sprite.parent removeChild:sprite cleanup:YES]; }
world->DestroyBody(body);
}
if (explode)
{
explosion = [[CCParticleSun alloc]initWithTotalParticles:250];
explosion.texture = [[CCTextureCache sharedTextureCache] addImage:#"fire.png"];
explosion.autoRemoveOnFinish = YES;
explosion.startSize = 15.0f;
explosion.speed = 30.0f;
explosion.position = p;
explosion.duration = 1.0f;
[self addChild:explosion z:self.zOrder+1];
}
What you want, then, is a way to create a particle emission system. My suggestion is to use a CAEmitterLayer. Ray Wenderlich has a great tutorial: UIKit Particle Systems in iOS 5 Tutorial
iPhone Programming Tutorial: Animating a Game Sprite
If you need to make an explosion another alternative would to use Cocos2d and do:
CCParticleSun *anExplosion=[CCParticleGalaxy node];
[kk setPosition:ball.position];
[self addChild:anExplosion];
Not really an animation, also, from the question you don't seem to be using Cocos2d, but if you start using it you can do this...
I need a way to create a collide effect, without the actual collision between the two images. Let me explain in more detail... If I have one fixed image and one image that is moving both images are on the same x coordinate at different positions. Basically I want the images appear to be colliding.I would want to run a check on the moving image like this...
If (front of moving image is clear)
{[move forward];}
else
{[stop];}
How would I implement this in code??? So that right before the moving image collides into the fixed image it stops, so that they appear to have collided.This check would also be running on a 1/60 NSTimer.
Any advice is welcome. Thank you.
Assuming the object is moving from the left
#define PIXELS_PER_FRAME 1
-(CGFloat) getCurrentX:(UIImage*)image
{
return image.frame.origin.x + image.frame.size.width;
}
-(void) moveImageToStableImage
{
CGFloat xTarget = stableImage.frame.origin.x;
if([self getCurrentX:movingImage] < xTarget)
{
movingImage.frame.origin.x += PIXELS_PER_FRAME;
[self performSelector:#selector(moveImageToStableImage) withObject:nil afterDelay:1.0/60];
}
}
But truth be told in this situation you would probably just be better off using an animation
everyone, I made a shooting game just like 1942(classic shooting game),but here's the question, FPS drops to 5~6 when the fighter shoot out a straight line of bullet,about 7~8 bullets in the screen,Actually, only 8 bullets of player will appear in games, when bullets fly out of the screen they would reset to the fighter's center and become invisible,all bullets are individual sprites, just like:
Sprites * bullet1 = [Sprite spriteWithFile:#"bullet.png"];
........
Sprites * bullet8 = [Sprite spriteWithFile:#"bullet.png"];
Is there any method can store a lots of bullets instead of defining them one by one??
Because enemies may fire too, I can imagine the FPS may get closer to zero.....
Can anyone help me??
you could do something like have a "bullet pool" in there, as you are using cocos, what I would do is to allocate lot's of bullets when I start the game. Check how many bullets do you need approximately, pre allocate those.
When an Entity in your game needs to fire a bullet, it just asks for a bullet to this pool, you give the properties to the "pre allocated" bullet, the bullet appears on the screen, and when it impacts/disappear you then return that bullet to your bullet pool.
if you need some code:
/*You pre-allocate your bullets.*/
for(int i = 0; i < MAX_BULLETS; i++)
{
Bullet *aBullet = [[Bullet alloc] init];
[bulletsArray addObject:aBullet];
[aBullet release];
}
//Then in game when you fire:
Bullet *aBullet = [PoolManager bulletWithSprite:myBulletSprite]; // Where myBulletSprite is PRE allocated and you don't allocate sprites in Game.
You can store the sprites in an array:
NSMutableArray * bulletsBuilder = [[NSArray alloc] init];
for(int i = 0; i < MAX_NUMBER_OF_SPRITES; ++i) {
[bullets addObject:[Sprite spriteWithFile:#"bullet.png"]];
}
NSArray * bullets = [NSArray arrayWithArray:bulletsBuilder];
[bulletsBuilder release];
And access them later using their identifier:
Sprite * spr = [bullets objectAtIndex:spriteIndex];
What's a problem? Use sprite batching! It's kind of special layer that allow you to speed up the rendering of the multiple sprites.
CCSpriteBatchNode* batch = [CCSpriteBatchNode batchNodeWithFile:#"bullet.png"];
Unless you're not Texture Atlas you cannot use different sprites to render them.
Then load one sprite and add to the batch itself as many sprites as you need.
for(;i>10;){[batch addSprite:sprite];}
Add to self.
Core Animation layers are lightweight and should help your performance. You can load the image once and then load the bullets image into the contents of an array of CALayers. Something like this:
// bulletImage is an instance variable
bulletImage = [UIImage imageNamed:#"bullet.png"];
bulletLayers = [[NSMutableArray alloc] init];
for (i = 0; i < 9; ++i)
{
CALayer *bulletLayer = [CALayer layer];
[bulletLayer setBounds:[bulletImage bounds]];
[bulletLayer setPosition:gunBarrelOrigin];
[bulletLayer setContents:(id)[bulletImage CGImage]];
[bulletLayers addObject:bulletLayer];
}
// Use the array of layers.
// ...
You don't specify whether you are using views or layers in your Sprite class, but if you are loading the same image multiple times, you're definitely creating unnecessary overhead.