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.)
Related
I have follow countless similar situations on here ( stack overflow ). I have applied those write ups for my situation and have come close but haven't found a solution that seems work for me. As this is something very trivial I am baffled at how it isn't working for me.
Anyways, I am trying to set a Int variable from inside the appDelegate class and the variable actually belongs, if that is the right word, to another class (mainViewController).
For the MainViewController class .h file I have
#interface MainWindowControllerViewController :... {
int relayState;
}
#property (readwrite, nonatomic) int relayState;
For the MainViewController class .m file I have
#implementation MainWindowControllerViewController
#synthesize relayState = _relayState;
-(void)quickConnect { // Call for all UI bypassing and quick kill
NSLog(#"Relay state in MainWindow = %d", relayState);
if (_relayState == 1) {
NSLog(#"TURNING ON KILL SWITCH");
self.writeData = [[NSString stringWithFormat:#"%#", #"e"] dataUsingEncoding:NSASCIIStringEncoding];
[sensor write:sensor.activePeripheral data:writeData];
} else {
NSLog(#"TURNING OFF KILL SWITCH");
self.writeData = [[NSString stringWithFormat:#"%#", #"o"] dataUsingEncoding:NSASCIIStringEncoding];
[sensor write:sensor.activePeripheral data:writeData];
}
}
For the appDelegate.h file I have
#import "MainWindowControllerViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
MainWindowControllerViewController *relayState;
}
#property (nonatomic, assign) MainWindowControllerViewController *relayState;
Then for the appDelegate.m file I have
#import "MainWindowControllerViewController.h"
#implementation AppDelegate
#synthesize relayState = _relayState;
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *) sourceApplication annotation:(id)annotation {
NSLog(#" Calling application: %#", sourceApplication);
NSLog(#" URL scheme: %#", [url scheme]);
if ([sourceApplication isEqualToString:#"URL-Scheme-Test"]) {
if ([[url scheme] isEqualToString:#"TurnOffRelay"]) {
_relayState =[[MainWindowControllerViewController alloc] init];
_relayState.relayState = 1;
NSLog(#"Relay State BEFORE = %d", _relayState.relayState);
}
return YES;
if ([[url scheme] isEqualToString:#"TurnOnRelay"]) {
_relayState =[[MainWindowControllerViewController alloc] init];
_relayState.relayState = 0;
NSLog(#"Relay State BEFORE = %d", _relayState.relayState);
}
return YES;
}
else
return NO;
}
This is pretty much it. When I do the logs I find that the relayState that I want to change the value of shows that I was able to change the value. But when I do the If statement above that checks weather the relayState is equal to 1 the variable is always 0.
I'm not the most proficient in Obj C. Some help would be appreciated! Thanks. I'll gladly answer any extra questions about code if needed.
You are kind of mixing some older style obj-c with how it usually looks currently and I think you are hiding a variable (one declaration is hiding another)
Take out:
{
int relayState;
}
From your MainWindowControllerViewController interface
Take out the #synthesize in the MainWindowControllerViewController implementation
Don't use _relayState (just use relayState)
Do the same with the MainWindowControllerViewController variable in the AppDelegate.
If that doesn't fix it, we need to see what is happening to the VC you are creating.
The problem I believe is this line
_relayState =[[MainWindowControllerViewController alloc] init];
You are initializing MainWindowControllerViewController in both the if blocks which is resetting the value to the default value (In this case 0) every time.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
MainWindowControllerViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"MainWindowControllerViewControllerIdentifier"];
vc.relayState = 1;
For the MainViewController class .h
#interface MainWindowControllerViewController :... {
int relayState; //remove this line
}
#property (nonatomic) int relayState; //use this
try this
You are making a mistake that will create endless problems for you.
You have a property named relayState and an instance variable named relayState.
The property "relayState" is backed by an instance variable named _relayState. You have another instance variable named relayState. Two different variables. Assigning to self.relayState changes one, assigning to relayState changes the other. Don't do it.
Just get rid of the "int relayState;" and don't use #synthesize and you'll be fine. At least a lot finer than you are now. You can then either use self.relayState or _relayState. At least you will always know what you are doing.
PS. Having an int relayState and a MainWindowViewController* relayState is just asking for trouble. You seem to be intentionally trying to confuse yourself.
PS. You seem to do the same dangerous game with the writeData property/variable.
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.
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
...
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];
OK I have a specific situation. I am using a custom class to create some buttons and I can set their tag property with unique numbers like:
button.tag =[NSNumber numberWithInt:[10]];
This is very useful in another part of my program because I can access this unique tag like:
UIButton *clicked= (UIButton *) sender;
ButtonTag = [NSString stringWithFormat:#"%d", clicked.tag];
Now I want to pass one more unique property just like this. I am making this up but this is how I envision it
button.tagCREATED_BY_ME =[NSNumber numberWithInt:[9000]];
The question might be poorly worded but I don't know any better so I called it "tag".(correct wording might be element/property etc) How do I create a similar property to function just like .tag?
Thanks a lot!
arda
What do you want to achieve?
There is the possibility of adding an associative references. The good part about this, is that you don't need to sub-class it. So, start by creating a Category for the UIButton:
#interface UIButton (ExtraTag)
#property (nonatomic, retain) id extraTag;
#end
And the .m:
static char const * const ExtraTagKey = "ExtraTag";
#implementation UIButton (ExtraTag)
#dynamic extraTag;
- (id)extraTag {
return objc_getAssociatedObject(self, ExtraTagKey);
}
- (void)setExtraTag:(id)newExtraTag {
objc_setAssociatedObject(self, ExtraTagKey, newExtraTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
You can check the article I used.
CALayer allows Key-Value coding actually.
You can literally just do this (on any UI object):
[button.layer setValue:#(9000) forKey:#"tagCREATED_BY_ME"];
and to read it just use
[button.layer valueForKey:#"tagCREATED_BY_ME"]
Obligatory, the above is all you need to get this up and going, you're good to go.
For others, more advanced /or/ specific stuff follows:
If you need these keys to have a default value when nothing has yet been assigned to them... You can set these custom "tags" (eh) to have default return values if you name them according to a pattern. For example I start all of my layer keys name's with "customKey_". So the above would have been #"customKey_tagCREATED_BY_ME", then you can have your .m file return the default key values for any standard key like masksToBounds but then return a very specific value for your keys (aka keys that start with "customKey_") with the following method:
+(id)defaultValueForKey:(NSString *)key {
if ([key hasPrefix:#"customKey_"]) {
return #(0);
}
return [CALayer defaultValueForKey:key];
}
The reason you have to have a naming pattern (like always having the prefix "customKey_") is so you don't interfere with a CALayer's natural properties like .size and .backgroundColor, etc. Your default value you want returned will only be returned on properties (key) starting with "customKey_" or whatever naming pattern you use.
In your subclassed/custom button, you can add a string property or even an integer property whichever you feel good.
#interface CustomButton: ....
...
#property(strong) NSString *createdBy;
#end
Then you can access those as aButton.createdBy
You can also use Associated references instead of tags manipulation
#import <objc/runtime.h>
static char kThumbnailButtonAssociatedPhotoKey;
// ...
- (void)setAssociatedPhoto:(Photo *)associatedPhoto
forThumbnailButton:(UIButton *)thumbnailButton
{
objc_setAssociatedObject(thumbnailButton,
&kThumbnailButtonAssociatedPhotoKey,
associatedPhoto,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (Photo *)associatedPhotoForThumbnailButton:(UIButton *)thumbnailButton
{
return objc_getAssociatedObject(thumbnailButton,
&kThumbnailButtonAssociatedPhotoKey);
}
Now we can easily set/get the associated photo for a button:
- (void)configureThumbnailButtonForPhoto:(Photo *)photo
{
// ...
[self setAssociatedPhoto:photo
forThumbnailButton:thumbnailButton];
// ...
}
- (void)thumbnailButtonTapped
{
Photo *photo = [self associatedPhotoForThumbnailButton:thumbnailButton];
// ...
}
Blog post about tags and associated references
You can subclass UIButton.
In your subclass, add a new property:
#property (strong, nonatomic) NSNumber *tagCREATED_BY_ME;
You could look into KVC.
Or if you wanted to stick to the KISS principle - subclass UIButton and create a property.