Nil label with spritebuilder, can't figure out how to fix it - ios

I am making an iOS game with sprite builder. And I designed it around a board game style. I want the user to press the play button that triggers the play method. It then generates a random number that should be displayed on a label. The label and button are on the gameplay scene. The game play scene is a subclass of CCNode. The code is on the Gameplay class that is a subclass of CCNode. I have found out that the label is nil. How do I make it not nil? The code connection for my label is doc root var assigned to _randNumLabel. My gameplay code connection is assigned Gameplay. This is my log after I open the scene and click the button:
2014-06-09 17:20:12.565 Sunk[6037:60b] CCBReader: Couldn't find member variable: _randNumLabel
2014-06-09 17:20:12.567 Sunk[6037:60b] CCBReader: Couldn't find member variable: _affectLabel
2014-06-09 17:20:19.513 Sunk[6037:60b] Nil`
Ignore the _affectLabel as it will get fixed if _randNumLabel gets fixed.
#import "Gameplay.h"
#implementation Gameplay
CCLabelTTF *_randNumLabel;
- (void)play {
if (_randNumLabel == nil)
{
CCLOG(#"Nil");
}
if (_randNumLabel !=nil)
{
CCLOG(#"play button pressed!");
int max = 6;
int randNumber = (arc4random() % max) + 1; // Generates a number between 1-6.
CCLOG(#"Random Number %d", randNumber);
_randNumLabel.string = [NSString stringWithFormat:#"Number: %d", randNumber];
}
}
- (void)update:(CCTime)delta {
}
#end

You need to declare your instance variables using curly brackets, i.e.:
#implementation Gameplay
{
CCLabelTTF *_randNumLabel;
}
- (void)play {
// rest of your code
...
As a personal preference I would use a private property instead of an instance variable, e.g.
#interface Gameplay ()
#property (nonatomic, strong) CCLabelTTF *randNumLabel;
#end
#implementation Gameplay
- (void)play {
// rest of your code
...

Related

Can't change "int" in Objective C

I have had a very weird experience with Objective C and xCode these last couple of days. I'm now turning to you guys for some quick help.
I'm simply trying to set up and int, call in damage(the amount of damage this object is supposed to do) and increase it if a void function is called.
-(void) increaseDagage{
damage = damage + 100;
NSLog(#"%f", damage);
}
I have tried setting the int damage up as a int and also as
#property (nonatomic, assign) float damage;
The problem is that when I print "damage" it hasn't increased...
I also have a function that returns the amount of damage this object does and it returns the wrong value.
I can't figure out why this isn't doing what I want...
I also have an int called health, which is basically the same thing and works fine.
Here's the full class if you want to see that too,
//
// Character.m
// TD
//
// Created by Victor Appelgren on 2014-12-23.
// Copyright (c) 2014 Victor Appelgren. All rights reserved.
//
#import "Character.h"
#import "constants.h"
#import "Level.h"
#import "GameViewController.h"
#interface Character (){
SKSpriteNode *character;
float health;
float maxHealth;
Level *level;
GameViewController *gVC;
BOOL dead;
int damage;
}
//#property (nonatomic, assign) float damage;
#end
#implementation Character
-(id) init {
if (self = [super init]){
damage = 100;
dead = NO;
// Load health
maxHealth = 200;
health = 200.0;
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:character.frame.size.width / 2];
[self addChild:character];
}
return self;
}
-(void) doDamageType:(int)type{ // here a type is passed in to tell how much damage is being done.
if (type == 1){
health = health - 20;
} else if (type == 2){
health = health - 40;
}
if (health <= 0){
[self removeFromParent];
dead = YES;
}
}
-(void) increaseDagage{
damage = damage + 100.0;
// NSLog(#"%f", _damage);
}
-(int) returnDamage{
return damage;
}
-(BOOL) returnDead{
return dead;
}
-(float) returnHealth{
return health;
}
-(float) returnMaxHealth{
return maxHealth;
}
#end
Here's the output I'm getting,
2015-02-22 01:28:27.722 TD[279:43180] 200.000000
2015-02-22 01:28:30.327 TD[279:43180] 200
2015-02-22 01:28:30.496 TD[279:43180] 200
2015-02-22 01:28:30.644 TD[279:43180] 200
2015-02-22 01:28:30.809 TD[279:43180] 200
first is initial value and the rest is from when the function is being called
What is wrong....
I might be missing something here but can't seem to find the problem
Thanks for the help
The problem is that you've created two different damage variables -- one in your .h and another in your .m. The one in your .h is public and accessible from your .m using self.damage. The one you've declared in your .m is private and accessible simply using damage. So the problem here is that you're accessing the public version of your damage from the other class, but you're actually manipulating the private version within your class.
So I'd recommend changing the following methods and property declarations of your .m as follows:
// ***Remove the private declaration of damage***
#interface Character (){
SKSpriteNode *character;
float health;
float maxHealth;
Level *level;
GameViewController *gVC;
BOOL dead;
}
#end
#implementation Character
// ***And add "self." before each instance of damage***
-(id) init {
if (self = [super init]){
self.damage = 100;
dead = NO;
// Load health
maxHealth = 200;
health = 200.0;
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:character.frame.size.width / 2];
[self addChild:character];
}
return self;
}
-(void) increaseDagage{
self.damage = self.damage + 100.0;
// NSLog(#"%f", self.damage);
}
-(int) returnDamage{
return self.damage;
}
#end
You have a spelling error in your method name : increaseDagage
I am guessing this should be increaseDamage
You also seem to be creating your own setters and getters. I would read up on the usage of properties.
Several things jump out:
Your method is called increaseDagage. Do you get any error message in Xcode's console when you call it?
You are not telling us whether you are getting any error or warning messages from the code. You should be getting some.
You keep talking about ints, but the log statement and property you define are floats.
You are not #synthesizeing your float damage property. So that means that it will create its own _damage instance variable to store the value and not use your damage instance variable (which would be the wrong type anyway).
You are logging _damage, not damage.
In short, the code, as written, mixes up two completely different things.

Getter & setter int value (NSObject) not passing from one ViewController to another

I'm building a game with 3 different level difficulties (Easy, Medium, & Delete) I have 2 ViewControllers and 1 NSObject class that I'm using to set and get the game difficulty value (0=easy, 1=Medium, 2=Delete(hard). Within context of how I'm doing it, I've research and tried many variations with no success. NOTE: I have tried to code this, but have since stripped out that part of the code because it wasn't working. I'm somewhat familiar with NSUserDefaults, so if that's a better solution, please advise. I may need a little direction on setting that up, though.
- ViewController 1 (RewindSettingsViewController): I have 3 buttons: Easy, Medium, Delete. User taps button, they go to ViewController 2
- ViewController 2 (RewindGameViewController): This is the actual game with a Start button. This is where I'm hung up; getting the difficulty passed into this view.
CODE:
.h - GameManager : NSObject
+(void) setDifficulty:(int)difficulty;
+(int) getDifficulty;
.m - GameManager
static int _difficulty;
+(void)setDifficulty:(int)difficulty {
_difficulty = difficulty;
}
+(int)getDifficulty {
return _difficulty;
}
(VC1) .h - RewindSettingsViewController : UIViewController
#property (nonatomic, strong) IBOutlet UIButton *easyModeButton;
#property (nonatomic, strong) IBOutlet UIButton *mediumModeButton;
#property (nonatomic, strong) IBOutlet UIButton *hardModeButton;
-(IBAction)easyMode;
-(IBAction)mediumMode;
-(IBAction)hardMode;
.m - RewindSettingsViewController
-(IBAction)easyMode {
[GameManager setDifficulty:0];
}
-(IBAction)mediumMode {
[GameManager setDifficulty:1];
}
-(IBAction)hardMode {
[GameManager setDifficulty:2];
}
(VC2) .h - RewindGameViewController : UIViewController
no code here for difficulty settings
.m - RewindGameViewController
At this point, _difficulty is of course still nil. My question marks below are my pain points
?: How to get the difficulty value stored in "setDifficulty" into "getDifficulty (_difficulty)" and properly call it in the IF statement?
?: I'm thinking _difficulty should be in the IF statements, but with everything I'm trying, syntax keeps barking at me.
-(void)placeObjectsRewind {
randomTopObjectRewind = arc4random() %350;
randomTopObjectRewind = randomTopObjectRewind - 228;
if (?) {
randomBottomObjectRewind = randomTopObjectRewind + 700; //LEVEL DIFFICULTY: EASY
objectTopRewind.center = CGPointMake(0, randomTopObjectRewind);
objectBottomRewind.center = CGPointMake(0, randomBottomObjectRewind);
} else if (?) {
randomBottomObjectRewind = randomTopObjectRewind + 665; //LEVEL DIFFICULTY: MEDIUM
objectTopRewind.center = CGPointMake(0, randomTopObjectRewind);
objectBottomRewind.center = CGPointMake(0, randomBottomObjectRewind);
} else if (?) {
randomBottomObjectRewind = randomTopObjectRewind + 635; //LEVEL DIFFICULTY: DELETE (HARD)
objectTopRewind.center = CGPointMake(0, randomTopObjectRewind);
objectBottomRewind.center = CGPointMake(0, randomBottomObjectRewind);
}
}
Instead of
static int _difficulty;
type this into your GameManager.h
#property int difficulty;
You don't have to write the Setter and Getter by yourself, the property-statement do this for you. The Getter/Setter is stored in the instance of GameManager you use. So get the instance of you GameManager and there you set like this:
[MyGameManagerInstance setDifficulty:0];
and get like
[MyGameManagerInstance difficulty];
Due to the fact that the difficulty-property is in the .h file, it's part of the Class's API which you can access from other ViewController or Classes.
EDIT:
Like you said, you could do this also with the NSUserDefaults. Just put it in like this:
[[NSUserDefaults standardUserDefaults] setInteger:1 forKey:#"Difficulty"];
and get it like this:
int myInt = [[NSUserDefaults standardUserDefaults] integerForKey:#"Difficulty"];
Since you've made the methods you want to use class methods, the syntax is going to be similar to if ([GameManager getDifficulty] == 0) etc.
(As a style point, you would usually drop the "get" in Objective-C and just name the method to return a value difficulty.)

Why can I not assign a value to my ivar?

it has been a while since I did anything in ObjC. I am sure the mistake is trivial but I can't seem to find it.
I created a class called Game with the following .h file:
#import <Foundation/Foundation.h>
#interface FSGame : NSObject
#property NSInteger numberOfGames;
#end
In the implementation file of one of my view controllers, a method then uses the user's selection from a segm. control to determine the number of games:
FSGame *game;
// Number of Games
NSInteger index = _segCtrlNumberGames.selectedSegmentIndex;
if (index == 0) {
game.numberOfGames = 1;
} else if (index == 1) {
game.numberOfGames = 3;
} else {
game.numberOfGames = 5;
}
NSLog(#"Games: %i; index: %i", game.numberOfGames, index);
The NSLog returns: Games: 0; index: 2
I have the same issue with two other classes I created. I grab text from a UITextField and the NSLog displays it correctly so I know I am actually able to get the user's input - it just wont store it as an ivar.
This must be something really obvious. Any pointers?
You create the Game object:
Game *game;
But you should create NSGame instead and you need to allocate and initialise it as well:
FSGame *game = [[FSGame alloc] init];

Append a string only once in objective c

I want to append a string only once when the view appears. Problem is, when I am moving back from previous view, text gets appended repeatedly. because I have kept the string appending code in viewWillAppear.
Here is the code,
if (!sharedController.perimeterFencesFreeOfHazard) {
NSString *origText = _messageLabel.text;
count++;
_messageLabel.text = [origText stringByAppendingString:#"\n • Perimeter fences & signs"];
//count++;
}
How to ensure string gets appended only once?
So you need a flag, which tells you if the text has been added for that view or not.
MyViewController.h:
#interface MyViewController : UIViewController {
BOOL _textAdded;
}
#end
MyViewController.m:
#implementation MyViewController
- (void)viewWillAppear {
if (!sharedController.perimeterFencesFreeOfHazard && !_textAdded) {
NSString *origText = _messageLabel.text;
count++;
_messageLabel.text = [origText stringByAppendingString:#"\n • Perimeter fences & signs"];
_textAdded = YES;
}
...
}
#end
In fact, it looks like you were going down that road with your count instance variable, which is just as good.
Move your code from viewWillAppear: to viewDidLoad:. As viewDidLoad: method is called just once when the view is created.

passing parameter to view in IOS after a button is pressed

I am new to IOS programming. So far I have been programming in android. So in android when pressing a button code for passing an argument would be like that:
Intent i = new Intent(MainScreen.this,OtherScreen.class);
Bundle b = new Bundle();
b.putString("data_1",data);
i.putExtras(b);
startActivity(i);
and on the activity that opens, i would write something like this:
Bundle b = getIntent().getExtras();
ski_center=b.getString("data_1");
what methods should I need to change in MainScreen and in OtherScreen in IOS to achieve the above.
Basically I will have 3 buttons lets say in my MainScreen and each of it will open the Otherview but each time a different parameter will be passed.
Foe example for each button i have code like these in MainScreen.m
#synthesize fl;
-(IBAction) ifl:(id) sender {
}
So I need your help in where to place the "missing" code, too.
Declare an iVar for your UIViewController ( Android's Activity) like a property in Java.
In MainViewController.m
OtherUIViewController * contr = [[OtherUIViewController alloc] initWithNibname...];
contr.data = yourData;
Edited: added full code...
Intent i = new Intent(MainScreen.this,OtherScreen.class);
Bundle b = new Bundle();
b.putString("data_1",data);
here the MainScreen is the calling code, now in iOS it will be the MainUIViewcontroller
create a OtherUIViewController like this:
OtherUIViewController.h
#interface OtherUIViewController : UIViewController
{
NSData* data;
}
#property (strong, nonatomic) NSData* data;
in the OtherUIViewController.m
#implementation OtherUIViewController.m
#synthetize data;
// override
- (void)viewDidLoad
{
[super viewDidLoad];
// do something with data here
}
to have the 3 different behaviors, the data can be an int, or an NSString.
And in the - (void)viewDidLoad you will check the data value and do 3 diff things.
I hope it helps

Resources