How To Change a Variable Name Depending on Another Variable? - iphone

I have a UIImageView called platform1, platform2, platform3, etc. I have an int called platformNumber coming from one method (method1) into another method (method2).
Method2 (contents not useful to my question):
CGPoint origin = platform1.center;
CGPoint target = CGPointMake(platform1.center.x, platform1.center.y+10);
CABasicAnimation *bounce = [CABasicAnimation animationWithKeyPath:#"position.y"];
bounce.duration = 0.1;
bounce.fromValue = [NSNumber numberWithInt:origin.y];
bounce.toValue = [NSNumber numberWithInt:target.y];
bounce.repeatCount = 1;
bounce.autoreverses = YES;
[platform1.layer addAnimation:bounce forKey:#"position"];
How do I change it so whereever platform1.center.x appears, it changes to platform[platformNumber] depending in the platformNumber value passed through?
Thanks, any help would be much appreciated!

The answers proposing KVC are not scalable at all; please don't do that. You can't declare a variable at runtime, so would will be stuck with however many image views you could attach a property too.
You need to build an array of your image views and iterate them. I repeat, KVC is not intended for this.
NSMutableArray *imageviews = [[NSMutableArray alloc] init];
//...
[imageViews addObject:platform1];
[imageViews addObject:platform2];
[imageViews addObject:platform3];
//...
Then iterate the array:
foreach (UIImageView *imgView in _imageViews) {
CGPoint origin = imgView.center;
CGPoint target = CGPointMake(imgView.center.x, imgView.center.y+10);
CABasicAnimation *bounce = [CABasicAnimation animationWithKeyPath:#"position.y"];
bounce.duration = 0.1;
bounce.fromValue = [NSNumber numberWithInt:origin.y];
bounce.toValue = [NSNumber numberWithInt:target.y];
bounce.repeatCount = 1;
bounce.autoreverses = YES;
[imgView.layer addAnimation:bounce forKey:#"position"];
}
int index = 3;
_imageViews[index]
returns you platform2 in your example (array start at 0, so subtract one)

Alternatively you can also create a function
-(UIImageView*)getPlatformForNumber:(int)number {
switch(number)
{
case 1:
return platform1;
case 2:
return platform2;
...
}
// should not come here
return nil;
}
and call that function where necessary. Sometimes that solution comes in handy - but the array proposed in davbryn's solution is of course more scalable.

Related

What is wrong with this attempt to create and populate an NSMutableArray?

In my .h file, I have:
#property (nonatomic) NSMutableArray *cards;
In my .m file, I have, in the initializer:
- (id) init
{
self = [super init];
self.cards = [NSMutableArray alloc];
return self;
}
In a loop that populates a number of items visible and on-screen:
[self.cards addObject:noteView];
And in a touch event handler, I have:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"In touchesBegan.");
UITouch *touch = [touches anyObject];
UIView *selectedView = nil;
CGPoint touchLocation = [touch locationInView:self.view];
for (UIView *card in _cards)
{
CGRect cardRect = [card frame];
NSLog(#"%f", cardRect.origin.x);
NSLog(#"%f", cardRect.origin.y);
NSLog(#"%f", cardRect.size.height);
NSLog(#"%f", cardRect.size.width);
if (CGRectContainsPoint(cardRect, touchLocation)) {
NSLog(#"Match found.");
selectedView = card;
CGRect selectedFrame = selectedView.frame;
selectedFrame.origin.y = -selectedFrame.size.height;
selectedFrame.size = selectedView.frame.size;
float heightRatio = (float) floor([[UIScreen mainScreen] bounds].size.height + .4) / (float) selectedFrame.size.height;
float widthRatio = (float) floor([[UIScreen mainScreen] bounds].size.width + .4) / (float) selectedFrame.size.width;
float ratio = MIN(heightRatio, widthRatio);
selectedFrame.size.height *= ratio;
selectedFrame.size.width *= ratio;
selectedFrame.origin.x = -selectedFrame.origin.x * ratio;
}
}
}
The output for every touch I've made has been that the unconditional NSLog statement is output, but none of the "Log this float" statements execute. It seems that I have not correctly initialized or not correctly populated NSMutableArray.
I seem to get the same behavior whether I refer to _cards or self.cards.
Thanks for any help,
--EDIT--
I seem to be sticking on something else than originally thought of. I now have self.cards = [[NSMutableArray alloc] init], but identical behavior: I go through a loop and populate a bunch of cards, but when I tap one of them, the touch handler outputs "In touchesBegan." but none of the floats. Given an updated init, why would touchesBegan be acting as if it hadn't seen any cards after a number of cards are visible onscreen? (The other output should give a number of lines of floats whether or not the touch was on target for a particular card.)
You need to init the array!
self.cards = [[NSMutableArray alloc] init];
Or
self.cards = [NSMutableArray new];
They are both equivalents
With alloc the only thing you are doing is reserve space in the memory for that variable.
From Apple Documentation:
alloc
Returns a new instance of the receiving class.
init
Implemented by subclasses to initialize a new object (the receiver) immediately after memory for it has been allocated.
Are you using a storyboard for this? Try to initialize your cards property in viewDidLoad.
As a quick check, try to initialize that property right before the loop that is adding objects to it.

Incompatible pointer types sending 'class' to parameter of type CCMenuItem

I am making a 14 year old kid making a game in cocos2d. I am pretty new to cocos2d. I want to display the same coin sprite next to each other to make a pattern.
So I added this in my main gameplay layer:
- (void)coinPatterns {
menu = [CCMenu menuWithItems:[Coins class], [Coins class], self, nil];
[menu alignItemsHorizontally];
[self addChild:menu];
}
And this is how I am initializing menu:
[[GameMechanics sharedGameMechanics] setSpawnRate:50 forMonsterType:menu];
This is what is in my coins class:
- (id)initWithMonsterPicture
{
self = [super initWithFile:#"coin.png"];
if (self)
{
CGRect screenRect = [[CCDirector sharedDirector] screenRect];
CGSize spriteSize = [self contentSize];
posX = screenRect.size.width + spriteSize.width * 0.5f;
posY = 150;
self.initialHitPoints = 1;
self.animationFrames = [NSMutableArray array];
[self scheduleUpdate];
inAppCurrencyDisplayNode.score = [Store availableAmountInAppCurrency];
}
coinValue = 3;
return self;
}
- (void)spawn
{
self.position = CGPointMake(posX, posY);
self.visible = YES;
}
- (void)gotCollected {
self.visible = FALSE;
self.position = ccp(-MAX_INT, 0);
[Store addInAppCurrency:coinValue];
}
I keep getting a Incompatible pointer types sending 'class' to parameter of type 'CCMenuItem'. Can someone please tell me how I should change the code so that this works?
Thanks!
menuWithItems: takes an array of CCMenuItem objects, you are sending a class itself. I don't know what the class Coin does, but if the purpose is to show an image and then do something when it's tapped I suggest you to do this:
CCMenuItem *myCoin1 = [CCMenuItemImage
itemFromNormalImage:#"coin.png" selectedImage:#"coinSelected.png"
target:self selector:#selector(coin1WasTapped:)];
CCMenuItem *myCoin2 ...
menu = [CCMenu menuWithItems: myCoin1, myCoin2, myCoin3, ..., nil];
You should create a method coin1WasTapped: that will be called when the coin was tapped, you can "collect" the coins here. Maybe remove them from the menu or an animation.
If you are going to create many coins I suggest you to use a for loop to create them all in an array. This way it will be easier to manipulate later.
This tutorial is really good, it can help you to understand better what you need to do and how to do it.
Good luck!

Sprites are disappear after some time

Here some code for Add sprite for Enemies.....
_robbers = [[CCArray alloc] initWithCapacity:kNumAstroids];
for (int i = 0; i < kNumAstroids; ++i) {
CCSprite *asteroid = [CCSprite spriteWithSpriteFrameName:#"robber.png"];
asteroid.visible = NO;
[_batchNode addChild:asteroid];
[_robbers addObject:asteroid];
}
And in Update method ........
double curTime = CACurrentMediaTime();
if (curTime > _nextRunemanSpawn) {
float randSecs = [self randomValueBetween:0.20 andValue:1.0];
_nextRunemanSpawn = randSecs + curTime;
float randY = [self randomValueBetween:80 andValue:80];
float randDuration = [self randomValueBetween:4.5 andValue:4.5];
float randDuration1 = [self randomValueBetween:1.0 andValue:1.0];
CCSprite *asteroid = [_robbers objectAtIndex:_nextRobber];
_nextRobber++;
if (_nextRobber >= _robbers.count) {
_nextRobber = 1;
}
[asteroid stopAllActions];
asteroid.position = ccp(winSize.width +asteroid.contentSize.width / 2 , randY);
asteroid.visible = YES;
[asteroid runAction:[CCSequence actions:[CCMoveBy actionWithDuration:randDuration position:ccp(-winSize.width-asteroid.contentSize.width, 0)],
[CCCallFuncN actionWithTarget:self selector:#selector(setInvisible:)],nil]];
All Sprites are Move from right to left in screen
when Sprite crosses the middle of the screen it automatically disappear
what is the reason for this problem ??
I agree with the previously mentioned statement from LearnCocos2D. It is also possible that you are adding multiple objects and reaching the end of the capacity in the line
_robbers = [[CCArray alloc] initWithCapacity:kNumAstroids];
If you try to spawn more objects than whatever number you have specified for kNumAsteroids it will remove the oldest object and use the new one in its place. I.e. if kNumAsteroids is 5, you have 5 on the screen and then add a sixth, 1 will become 6 and its position will be whatever you set it to.

How to do this in Cocos2d?

Sorry about the poor question title, it's just that this seems to big for a title. So here's the dirt:
I am making a game (obviously) and I want the enemies to shoot (not necessarily at the player). I want the shoot method to be in the Enemies file, so as not to clutter up my HelloWorldLayer.m file even more. Here's what I'm using right now:
HelloWorldLayer.m
-(void)addEnemy:(BigAndStrongEnemy *)enemy {
enemy = nil;
if((arc4random() % 4) == 3) {
enemy = [BigAndStrongEnemy enemy];
} else {
enemy = [SmallAndFastEnemy enemy];
}
if(buffDude.position.y > character.position.y || buffDude.position.y < (character.position.y + 10)) {
}
int rand = arc4random() % 320;
if((arc4random() % 2 == 1)) {
[enemy setPosition:ccp(0,rand)];
}else{
[enemy setPosition:ccp(480,rand)];
}
[self animateEnemy:enemy];
[self addChild:enemy];
}
-(void)animateEnemy:(BigAndStrongEnemy *)enemy2 {
float randX = arc4random() % 480;
float randY = arc4random() % 320;
int rand = arc4random() % 320;
CGPoint moveToPoint = CGPointMake(randX, (randY - rand));
[enemies addObject:enemy2];
action = [CCSequence actions:
[CCMoveBy actionWithDuration:1 position:ccpMult(ccpNormalize(ccpSub(moveToPoint, enemy2.position)), 75)],
[CCMoveBy actionWithDuration:3 position:ccp(buffDude.position.x,buffDude.position.y)],
nil];
CCCallFuncO *a = [CCCallFuncO actionWithTarget:self selector:(#selector(shoot:)) object:enemy2];
CCSequence *s = [CCSequence actions:action,a, nil];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:s];
[enemy2 runAction:repeat];
}
And here's the Shoot info from the Enemies class:
Enemies.m:
-(void)shoot:(id)sender {
BigAndStrongEnemy *enemy = (BigAndStrongEnemy *)sender;
[enemy shoot];
}
-(void)spriteMoveFinished:(id)sender {
CCSprite *b = (CCSprite *)sender;
[self removeChild:b cleanup:YES];
}
-(void)shoot {
buffDude = [CCSprite spriteWithFile:#"bigAndStrongEnemy.gif"];
CCSprite *b = [CCSprite spriteWithFile:#"bullet.gif"];
b.position = ccp(self.position.x,self.position.y);
b.tag = 2;
[self addChild:b];
[bullets addObject:b];
CGSize winSize = [[CCDirector sharedDirector] winSize];
CGPoint point = CGPointMake((winSize.width - (winSize.width - self.position.x)),0);
[b runAction:[CCSequence actions:
[CCMoveBy actionWithDuration:0.5 position:point],
[CCCallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)],
nil]];
}
Every time the 3 seconds goes by, the app crashes, and goes to the breakpoint in the CCCallFuncO file. I haven't touched it, is the thing. I am completely confused. Any help is greatly appreciated. Sorry about the long question. Thanks!!
It looks like your CCCallFuncO is calling [self shoot:enemy2] where self is the HelloWorldLayer object, but shoot is defined in the Enemies class.
Edit:
buffDude should be released before assigning it and retain it afterwards, like this:
Change this:
buffDude = [CCSprite spriteWithFile:#"bigAndStrongEnemy.gif"];
to this:
[buffDude release];
buffDude = [CCSprite spriteWithFile:#"bigAndStrongEnemy.gif"];
[buffDude retain];
This assumes that this is the only place where buffDude is assigned. If it is also assigned elsewhere, make sure you properly retain and release it there as well.
Although, the more I think about it, I don't understand why you create a new buffDude every time shoot is called. I'm not sure what you're doing, so I won't say it's wrong, but it doesn't look right to me anyway.
from what i see (and the fact that i only worked with cocos2d-x) i can only tell you to test whether it steps inside your shoot funciton or not, but i guess you are somhow using CCCallFuncO bad, maybe you have to call it passing enemy2 also for the actionWithTarget parameter (i can tell that becouse that's how cocos2d-x works), also check if big and small enemy types can be converted together freely.

removing integers from an array

I need to make an array for the co ordinates of my sprites and i wanted to remove the co-ordinate once the sprite has that co-ordinate from the array as i don't want another sprite having the same co-ordinate, i can't seem to get it to work, there are no errors and when debugging it says nsexception and quits. what am i doing wrong and where do i deallocate the arrays? when i release them in dealloc it says i need to declare them.
CGPoint cg1 = CGPointMake(33,33);
NSValue *cg1obj = [NSValue valueWithCGPoint:cg1];
CGPoint cg2 = CGPointMake(33,97);
NSValue *cg2obj = [NSValue valueWithCGPoint:cg2];
NSMutableArray *numberxy = [[NSMutableArray alloc] init]; int pointcount = 0;
[numberxy insertObject:cg1obj atIndex:pointcount++];
[numberxy insertObject:cg2obj atIndex:pointcount++];
NSMutableArray *sprites = [[NSMutableArray alloc] init]; int spritecount = 0;
[sprites insertObject:red1 atIndex:spritecount++];
[sprites insertObject:red2 atIndex:spritecount++];
for (int i=0; i<3;i++) {
int rpoint = arc4random() % 3;
int rsprite = arc4random() % 3;
CGPoint point = [[numberxy objectAtIndex:rpoint] CGPointValue];
CCSprite *sprite1 = [sprites objectAtIndex:rsprite];
sprite1.position = ccp(point.x,point.y);
if (sprite1.position.x == point.x && sprite1.position.y == point.y) {
[numberxy removeObjectAtIndex:rpoint];
[sprites removeObjectAtIndex:rsprite];
}
}
Your code is weird. Why is xValue defined after it is used? You may have a leak if xValue was defined previously in the same manner and now you are redefining xValue. You then check if X is in the new xValue. There is nothing in the new xValue so the if statement will evaluate to false, so nothing will be removed.
NSNumber *X = [NSNumber numberWithInt:randomNumberx];
[xValue containsObject: numberx];
xValue = [[NSMutableArray alloc]init];
if ([xValue containsObject:X]) {
[numberx removeObject:X];
}
Also what is the point of [xValue containsObject: numberx]; outside of the if statement? It doesn't have a purpose.