I've been reading this book on game programming, but the examples are not that great. I'm working on one that calls [self setNeedsDisplay] but it cause the app the crash.
This is all the code I have, copied verbatim from the book:
-(void)awakeFromNib {
//start timer that will fire every second
[car setAlpha:0];
[road setAlpha:0];
currentImage = [UIImage imageNamed:#"road.png"];
//start timer that fires every second
[NSTimer scheduledTimerWithTimeInterval:(1.0) target:self selector:#selector(onTimer) userInfo:nil repeats:YES];
//start timer that fires every hundreth of a second
[NSTimer scheduledTimerWithTimeInterval:(0.01) target:self selector:#selector(onTimerRoad) userInfo:nil repeats:YES];
}
-(void)onTimerRoad
{
int tileIndex;
tileIndex += 1;
[self setNeedsDisplay];
}
-(void)onTimer {
[self update];
[self draw];
}
-(void)update {
[self updateRoad];
}
-(void)updateRoad {
[self randomRoadUpdate];
}
-(void)randomRoadUpdate {
int distance = (random() % 11) -5;
CGPoint oldPosition = road.center;
if (oldPosition.x + distance < 96 || oldPosition.x + distance > 224)
return;
road.center = CGPointMake(oldPosition.x + distance, oldPosition.y);
}
-(void)draw {
}
- (id) initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
//init code
}
return self;
}
-(void)drawRect:(CGRect)rect {
CGImageRef image = CGImageRetain(currentImage.CGImage);
CGRect imageRect;
imageRect.origin = CGPointMake(160, 240);
imageRect.size = CGSizeMake(320.0, 480.0);
CGContextRef uiContext = UIGraphicsGetCurrentContext();
CGContextClipToRect(uiContext, CGRectMake(0.0, 0.0, rect.size.width, rect.size.height));
CGContextDrawTiledImage(uiContext, imageRect, image);
}
Turns out instead of [self setNeedsDisplay] I need to do [self.view setNeedsDisplay]
Related
Hello I am making a cocos2d side scroller app and I want enemies to fly at the character at random. I am a beginner to objective c and cocos2d so this may seem like a simple question but any help is valuable. Would arc4random help??
Here is my code so far. I want it so that one of these four methods: redEnemyFlight, yellowEnemyFloating, blueEnemyFlight, and spinTheRock is called randomly one at a time in an endless loop one after another.
#import "FlyingEnemy.h"
#implementation FlyingEnemy
+(id)createEnemies{
return [[[self alloc]init]autorelease];
}
-(id)init{
if((self = [super init])){
CGSize size = [[CCDirector sharedDirector]winSize];
screenWidth = size.width;
screenHeight = size.height;
screenBounds = [[UIScreen mainScreen] bounds];
redEnemyFlameCounter = 1;
xPoint = screenWidth - 50;
yPoint = screenHeight/2;
yellowEnemyFlameCounter = 1;
blueEnemyFlameCounter = 1;
xPointBlueEnemy = screenWidth - 50;
yPointBlueEnemy = screenHeight - 50;
[self spinTheRock];
}
return self;
}
-(void)spinTheRock{
spinningRock = [CCSprite spriteWithFile:#"rocks.png"];
spinningRock.position = ccp(screenWidth * 1.5, screenHeight/2);
[self addChild:spinningRock z:-1];
[spinningRock runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:2.0 angle:360]]];
moveTheRock = [CCMoveTo actionWithDuration:39.0 position:ccp(-500, spinningRock.position.y)];
[spinningRock runAction:moveTheRock];
[self schedule:#selector(removeTheSpinningRock:)interval:10.0f/1.0f];
}
-(void)removeTheSpinningRock:(ccTime)delta{
[self unschedule:#selector(removeTheSpinningRock:)];
[self stopAllActions];
[self createFlyingEnemy];
}
-(void)redEnemyFlight{
redEnemy = [CCSprite spriteWithFile:#"redenemy.png"];
redEnemy.position = ccp(xPoint, yPoint);
[self addChild:redEnemy z:-1];
[self schedule:#selector(shootTheBullets:)interval:1.0f/2.0f];
[self schedule: #selector(removeTheEnemy:)interval:18.0f/1.0f];
[self schedule: #selector(redEnemyFlame:)interval:1.0f/5.0f];
}
-(void)redEnemyFlame:(ccTime)delta{
redEnemyFlameCounter ++;
if (redEnemyFlameCounter % 2){
[redEnemy setTexture:[[CCSprite spriteWithFile:#"redenemy2.png"]texture]];
}else{
[redEnemy setTexture:[[CCSprite spriteWithFile:#"redenemy.png"]texture]];
}
}
-(void)removeTheEnemy:(ccTime)delta{
CCMoveBy* moveUp = [CCMoveBy actionWithDuration:2.0 position:ccp(100, screenHeight/2)];
[redEnemy runAction:moveUp];
[self unschedule:#selector(removeTheEnemy:)];
}
-(void)yellowEnemyFloating{
yellowEnemy = [CCSprite spriteWithFile:#"yellowenemy.png"];
yellowEnemy.position = ccp(screenWidth - 50, 50);
[self addChild:yellowEnemy z:-1];
yellowEnemyMoveDown = [CCMoveTo actionWithDuration:2.0 position:ccp(yellowEnemy.position.x, 50)];
yellowEnemyMoveUp = [CCMoveTo actionWithDuration:2.0 position:ccp(yellowEnemy.position.x, screenHeight/2)];
yellowEnemyFloatingSequnece = [CCSequence actions:yellowEnemyMoveUp, yellowEnemyMoveDown, nil];
yellowEnemyFloatingRepeat = [CCRepeat actionWithAction:yellowEnemyFloatingSequnece times:2];
[yellowEnemy runAction:yellowEnemyFloatingRepeat];
[self schedule: #selector(yellowEnemyFlame:)interval:1.0f/5.0f];
}
-(void)yellowEnemyFlame:(ccTime)delta{
yellowEnemyFlameCounter ++;
if (yellowEnemyFlameCounter % 2){
[yellowEnemy setTexture:[[CCSprite spriteWithFile:#"yellowenemy2.png"]texture]];
}else{
[yellowEnemy setTexture:[[CCSprite spriteWithFile:#"yellowenemy.png"]texture]];
}
[self schedule:#selector(yellowEnemyFlight:)interval:8.0f/1.0f];
}
-(void)yellowEnemyFlight:(ccTime)delta{
yellowEnemyMoveLeft = [CCMoveTo actionWithDuration:4.0 position:ccp(-100, bulletY)];
[yellowEnemy runAction:yellowEnemyMoveLeft];
[self schedule:#selector(removeTheYellowEnemy:)interval:4.0f/1.0f];
}
-(void)removeTheYellowEnemy:(ccTime)delta{
CCMoveTo* removeYellowEnemy = [CCMoveTo actionWithDuration:1.0 position:ccp(-100, screenHeight/2)];
[yellowEnemy runAction:removeYellowEnemy];
[self unschedule:#selector(removeTheYellowEnemy:)];
}
-(void)blueEnemyFlight{
blueEnemy = [CCSprite spriteWithFile:#"blueenemy.png"];
blueEnemy.position = ccp(xPointBlueEnemy, yPointBlueEnemy);
[self addChild:blueEnemy z:-1];
[self schedule:#selector(shootTheWaterBullets:)interval:1.0f/2.0f];
CCMoveTo* blueEnemyMoveDown = [CCMoveTo actionWithDuration:3.0 position:ccp(xPointBlueEnemy, 70)];
CCMoveTo* blueEnemyMoveUp = [CCMoveTo actionWithDuration:3.0 position:ccp(xPointBlueEnemy, yPointBlueEnemy - 10)];
CCSequence* blueEnemyFloatingSequence = [CCSequence actions:blueEnemyMoveDown, blueEnemyMoveUp, nil];
CCRepeat* blueEnemyFloatingRepeat = [CCRepeat actionWithAction:blueEnemyFloatingSequence times:3];
[blueEnemy runAction:blueEnemyFloatingRepeat];
[self schedule: #selector(removeTheBlueEnemy:)interval:18.0f/1.0f];
[self schedule: #selector(blueEnemyFlame:)interval:1.0f/5.0f];
}
-(void)blueEnemyFlame:(ccTime)delta{
blueEnemyFlameCounter ++;
if (blueEnemyFlameCounter % 2){
[blueEnemy setTexture:[[CCSprite spriteWithFile:#"blueenemy2.png"]texture]];
}else{
[blueEnemy setTexture:[[CCSprite spriteWithFile:#"blueenemy.png"]texture]];
}
}
-(void)removeTheBlueEnemy:(ccTime)delta{
CCMoveBy* moveUpBlueEnemy = [CCMoveBy actionWithDuration:0.5 position:ccp(200, 400)];
[blueEnemy runAction:moveUpBlueEnemy];
[self unschedule:#selector(removeTheBlueEnemy:)];
}
-(void) createFlyingEnemy{
// I am assuming you have an Enemy class or equivalent,
// and that it subclasses from CCNode somehow
NSUInteger randomEnemy = arc4random() % 3; // will return 0-3
return [self createEnemyOfType:randomEnemy];
}
-(void) createEnemyOfType:(NSUInteger) enemyType {
switch(enemyType) {
case 0: return [self redEnemyFlight];
case 1: return [self yellowEnemyFloating];
case 2: return [self blueEnemyFlight];
default : return [self spinTheRock];
}
}
-(void)checkForOverlap{
if (isRedEnemyOnTheScreen == YES) {
[self removeChild:yellowEnemy cleanup:YES];
[self removeChild:blueEnemy cleanup:YES];
[self removeChild:spinningRock cleanup:YES];
}
if (isYellowEnemyOnTheScreen == YES) {
[self removeChild:redEnemy cleanup:YES];
[self removeChild:blueEnemy cleanup:YES];
[self removeChild:spinningRock cleanup:YES];
}
if (isBlueEnemyOnTheScreen == YES) {
[self removeChild:redEnemy cleanup:YES];
[self removeChild:yellowEnemy cleanup:YES];
[self removeChild:spinningRock cleanup:YES];
}
if (isSpinningRockOnTheScreen == YES) {
[self removeChild:redEnemy cleanup:YES];
[self removeChild:yellowEnemy cleanup:YES];
[self removeChild:blueEnemy cleanup:YES];
}
}
#end
I would add something like this to your controller:
// in your .h add a few iVars
float minDelay,maxDelay;
BOOL spawnEnabled;
// in your init setup a couple of iVars
minDelay = 0.5; // seconds
maxDelay = 2.0; // seconds
spawnEnabled = NO;
// where you are ready to spawn
spawnEnabled = YES;
[self scheduleOnce:#selector(spawnOneEnemy) delay:0.];
// add the spawning method
-(void) spawnOneEnemy {
if(!spawnEnabled) return; // prevent spawning if this was called
// after a gameOver or Win was declared
// here, compute the random x,y coords where you want to spawn
CGPoint spawnCoords = [self randomSpawnCoordinates];
// create and add an enemy at the random coordinate
Enemy * enemy = [self createEnemy];
enemy.position = spawnCoords;
[self addChild enemy]; // assumes 'self' is a CCNode subclass
// compute the next spawn time
u_int32_t delta = (u_int32_t) (ABS(maxDelay-minDelay)*1000); // ms resolution
float randomDelta = arc4random_uniform(delta)/1000.; // now in seconds
[self scheduleOnce:#selector(spawnOneEnemy) delay:randomDelta];
}
// where you win
spawnEnabled = NO;
// where you lose
spawnEnabled = NO;
// left as an exercise to the reader :
-(CGPoint) randomSpawnCoordinates {
}
-(Enemy *) createEnemy {
// I am assuming you have an Enemy class or equivalent,
// and that it subclasses from CCNode somehow
NSUInteger randomEnemy = arc4random_uniform(4); // will return 0-3
return [self createEnemyOfType:randomEnemy];
}
-(Enemy *) createEnemyOfType:(NSUInteger) enemyType {
// assumes all your enemy types subclass Enemy
switch(enemyType) {
case 0: return [self createEnemyOfType0];
case 1: return [self createEnemyOfType1];
case 2: return [self createEnemyOfType2];
case 3: return [self createEnemyOfType3];
default : return [self createEnemyOfType1];
}
}
EDIT : clarified the iVars declarations.
EDIT : put in some thoughts for random enemies
I am trying animation, where the UITableView is already in place,but the subview (which itself contains the cell's content view) for each of the UITableViewCells is outside the window bounds. It is outside the screen. When the view loads, the cell animate from left to right, one by one, till the rightmost x value of the frame touches the rightmost x value of the UITableView.
The animation is such that, once first cell takes off, the second cell takes off before the first cell is finished with it's animation. Similarly, the third cell takes off before the second is finished with it's animation. However, i am not able to achieve this, and i all my rows animate all-together.
-(void)animateStatusViewCells:(SupportTableViewCell *)cell
{
__block CGPoint center;
[UIView animateWithDuration:0.55 delay:0.55 options:UIViewAnimationOptionCurveEaseIn animations:^{
center = cell.statusView.center;
center.x += (cell.frame.size.width - 20);
cell.statusView.center = center;
}completion:^(BOOL success){
NSLog(#"Translation successful!!!");
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//[self animateStatusViewCells:cell];
});
}];
}
-(void)animateSupportTableView:(UITableView *)myTableView
{
NSMutableArray *cells = [[NSMutableArray alloc] init];
NSInteger count = [myTableView numberOfRowsInSection:0];
for (int i = 0; i < count; i++) {
[cells addObject:[myTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]]];
}
for (SupportTableViewCell *cell in cells) {
[self animateStatusViewCells:cell];
}
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self animateSupportTableView:_statusTableView];
}
Here's the initWithStyle method for the custom UITableViewCell:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
_statusView = [[UIView alloc] initWithFrame:self.frame];
self.contentView.backgroundColor = [UIColor greenColor];
self.contentView.alpha = 0.7;
CGPoint cellCenter = self.center;
cellCenter.x = self.center.x - (self.frame.size.width - 20);
_statusView.center = cellCenter;
[self addSubview:_statusView];
[_statusView addSubview:self.contentView];
}
return self;
}
You need to use a different delay value for each animation. Instead of using a constant delay of .55, pass in the cell number to your animate method, and use something like:
CGFloat delay = .55 + cellNumber * cellDelay;
[UIView animateWithDuration: 0.55 delay: delay options:UIViewAnimationOptionCurveEaseIn animations:
^{
//animation code
}
];
For what its worth, this is a clean solution:
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let trans = CATransform3DMakeTranslation(-cell.frame.size.width, 0.0, 0.0)
cell.layer.transform = trans
UIView.beginAnimations("Move", context: nil)
UIView.setAnimationDuration(0.3)
UIView.setAnimationDelay(0.1 * Double(indexPath.row))
cell.layer.transform = CATransform3DIdentity
UIView.commitAnimations()
}
try this
declare this somewhere.
int c=0;
-(void)animateStatusViewCells:(SupportTableViewCell *)cell
{
__block CGPoint center;
[UIView animateWithDuration:0.55 delay:0.55 options:UIViewAnimationOptionCurveEaseIn animations:^{
center = cell.statusView.center;
center.x += (cell.frame.size.width - 20);
cell.statusView.center = center;
}completion:^(BOOL success){
c++;
if(c<[cells count]){
[self animateStatusViewCells:[cells objectAtIndex:c]];
}
}];
}
-(void)animateSupportTableView:(UITableView *)myTableView
{
NSMutableArray *cells = [[NSMutableArray alloc] init];
NSInteger count = [myTableView numberOfRowsInSection:0];
for (int i = 0; i < count; i++) {
[cells addObject:[myTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]]];
}
[self animateStatusViewCells:[cells objectAtIndex:c]];
}
After some research on here I found a solution to creating a slide show of images in an iphone app. All working fine, currently the images show one after another.
My question is, can I make the images cross dissolve/fade rather than just appearing, and if so could I get some advice on that.
My Code
.m
}
int topIndex = 0, prevTopIndex = 1;
- (void)viewDidLoad
{
imagebottom = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,160,240)];
[self.view addSubview:imagebottom];
imagetop = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,160,240)];
[self.view addSubview:imagetop];
imageArray = [NSArray arrayWithObjects:
[UIImage imageNamed:#"image1.png"],
[UIImage imageNamed:#"image2.png"],
[UIImage imageNamed:#"image3.png"],
[UIImage imageNamed:#"ip2.png"],
nil];
NSTimer *timer = [NSTimer timerWithTimeInterval:5.0
target:self
selector:#selector(onTimer)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[timer fire];
[super viewDidLoad];
}
-(void)onTimer{
if(topIndex %2 == 0){
[UIView animateWithDuration:5.0 animations:^
{
imagebottom.alpha = 0.0;
}];
imagetop.image = [imageArray objectAtIndex:prevTopIndex];
imagetop.image = [imageArray objectAtIndex:topIndex];
}else{
[UIView animateWithDuration:5.0 animations:^
{
imagetop.alpha = 1.0;
}];
imagetop.image = [imageArray objectAtIndex:topIndex];
imagebottom.image = [imageArray objectAtIndex:prevTopIndex];
}
prevTopIndex = topIndex;
if(topIndex == [imageArray count]-1){
topIndex = 0;
}else{
topIndex++;
}
You have a bunch of options. If you have a "container" view, you can make a new UIImageView transparent (alpha = 0), then use a UIView animation block to fade one image in and the other out (or leave alpha = 1 on both and slide one in from any side you want.
For instance, you have your main view, self.view. You have one UIImageView *oldView, that is now at rect (0,0,320,100) and you want to slide it to the right as you slide a newView imageView in. First you set the newView frame to (-320,0,320,100) then [self.view addSubview newView]. To animate the change:
[UIView animateWithDuration:2 animations:^
{
oldView.frame = CGRectMake(320, 0, 320, 100);
newView.frame = CGRectMake(0,0,320, 100);
}
completion:^(BOOL finished)
{
[oldView removeFromSuperView];
} ];
You also have the option of using UiView's
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion
which gives you more/different options (and its less work too!). For instance, using the same basic objects in the first example, but the newView having the same frame as the oldView:
transitionFromView:oldView toView:newView duration:2 options: UIViewAnimationOptionTransitionCrossDissolve completion:^(BOOL finished)) { /*whatever*/}];
Hey everyone I am making an app where you're a blue ball and have to move without letting the red ball touch you and I was wondering what could I do so that every second the velocity increases I have something like this:
- (void)viewDidLoad {
[super viewDidLoad];
//(X Speed, Y Speed)
pos = CGPointMake(13.0,8.0);
pos2 = CGPointMake(10.0,9.0);
}
- (IBAction)restart:(id)sender {
[restartbutton setHidden:YES];
[menubutton setHidden:YES];
randomMain = [NSTimer scheduledTimerWithTimeInterval:(0.03) target:self selector:#selector(onTimer) userInfo:nil repeats:YES];
}
- (IBAction)start:(id)sender {
[startbutton setHidden:YES];
[restartbutton setHidden:YES];
[menubutton setHidden:YES];
randomMain = [NSTimer scheduledTimerWithTimeInterval:(0.03) target:self selector:#selector(onTimer) userInfo:nil repeats:YES];
}
- (IBAction)menu:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
- (void)onTimer {
[self checkCollision];
enemy.center = CGPointMake(enemy.center.x+pos.x, enemy.center.y+pos.y);
enemy2.center = CGPointMake(enemy2.center.x+pos2.x, enemy2.center.y+pos2.y);
if (enemy.center.x > 320 || enemy.center.x < 0)
pos.x = -pos.x;
if (enemy.center.y > 480 || enemy.center.y < 0)
pos.y = -pos.y;
if (enemy2.center.x > 320 || enemy2.center.x < 0)
pos2.x = -pos2.x;
if (enemy2.center.y > 480 || enemy2.center.y < 0)
pos2.y = -pos2.y;
}
- (void)checkCollision {
if (CGRectIntersectsRect(player.frame, enemy.frame)) {
[randomMain invalidate];
[startbutton setHidden:YES];
[restartbutton setHidden:NO];
[menubutton setHidden:NO];
CGRect frame = [player frame];
frame.origin.x = 135.0f;
frame.origin.y = 205.0f;
[player setFrame:frame];
CGRect frame2 = [enemy frame];
frame2.origin.x = 135.0f;
frame2.origin.y = 20.0f;
[enemy setFrame:frame2];
CGRect frame3 = [enemy2 frame];
frame3.origin.x = 135.0f;
frame3.origin.y = 390.0f;
[enemy2 setFrame:frame3];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"You Lost!"
message:[NSString stringWithFormat:#"Better Luck Next Time"]
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
[alert show];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *myTouch = [[event allTouches] anyObject];
player.center = [myTouch locationInView:self.view];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
#end
It seems that the only method you've given us that is being constantly called is onTimer. Why don't you set an acceleration constant of something really small like 0.01. Then, create a method called accelerate and put in code to the effect of:
pos = CGPointMake(pos.x + ACC_CONSTANT, pos.y + ACC_CONSTANT);
pos2 = CGPointMake(pos2.x + ACC_CONSTANT, pos.y + ACC_CONSTANT);
Call accelerate after [self checkCollision];
Then play around with the Acceleration constant until you get the results you want.
If you want it to be a step function where it only increases every second, you will need to use an NSTimer iVar, which would also be fairly easy. Just instantiate it with a one second time interval using this init function
scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
Then call #selector(accelerate) as the target selector.
What I want to realize is:
When I touch a button, the image display on the view for 1 sec, then the image disappear.
I know that a NSTimer will help, but i dont know how to write the right code...need your help, thanks.
- (IBAction)bodytouched:(id)sender {
bodytouchedimage.hidden = NO;
bodytouchedimage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"beated.jpg"]];
bodytouchedimage.userInteractionEnabled = YES;
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(showPictures:) userInfo:nil repeats:NO];
}
- (void)showPictures:(NSTimer *)timer {
bodytouchedimage.hidden = YES;
}
What you should to is call the showPictures function when you touch the button and then within the showPictures method you add a NSTimer that will call a hidePictures method 1 second later
- (void)showPictures
{
bodytouchedimage.hidden = NO;
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(hidePictures) userInfo:nil repeats:NO];
}
- (void)hidePictures
{
bodytouchedimage.hidden = YES;
}
Rather than using NSTimer, it would be easier to simply call your method to hide the image like this:
- (IBAction)bodytouched:(id)sender {
bodytouchedimage.hidden = NO;
bodytouchedimage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"beated.jpg"]];
bodytouchedimage.userInteractionEnabled = YES;
[self performSelector:#selector(hidePicture) withObject:nil afterDelay:1];
}
- (void)hidePicture {
bodytouchedimage.hidden = YES;
}
performSelector:withObject:afterDelay: is a method of the NSObject class.